빈 문자열은 언제 현재 디렉터리를 나타냅니까?

빈 문자열은 언제 현재 디렉터리를 나타냅니까?

find다음과 같이 현재 디렉터리의 일부 파일을 수집하는 데 사용하는 스크립트에서

$ find . -name "*.h"
./foo.h

foo.h이제 접두사 없이 그냥 출력하고 싶습니다 ./. 나는 빈 문자열이 ""쉘 명령의 현재 디렉토리를 나타내는 것이라고 생각했습니다. 그러나 이것은 다음을 제공합니다:

$ find "" -name "*.h"
find: ftsopen: No such file or directory

그래서 나는 틀렸다. 이제 내 질문은 언제/어떻게/어디에서/.. 파일 이름이나 경로 이름이 필요한 명령에서 "빈 문자열(?)"이 현재 디렉터리를 나타내는가입니다. 깔끔하고 이해하기 쉬운 설명이 있나요?

부가적인 질문은 위의 문제 찾기가 문자열 조작(a la ${parameter#word}또는 cut또는 sed?) 없이 간단하게 해결될 수 있는지 여부입니다.

답변1

아주 오래전(에 7판, 32V, 4.2BSD, 4.3BSD), 시스템 호출 수준에서 길이가 0인 경로 이름은 현재 작업 디렉터리를 나타냅니다(조회에 사용될 때 파일이나 디렉터리를 생성하거나 삭제하려고 할 때 허용되지 않습니다). ~ 안에 시스템 III, 모든 상황에서 길이가 0인 경로 이름을 사용하는 것은 오류였으며POSIX 표준경로 이름 확인에 대해 다음과 같이 말합니다.

null 경로 이름은 성공적으로 해결되지 않습니다.

답변2

당신이 사용할 수있는:

find * -name "*.h"

이름이 로 시작하는 현재 디렉토리의 파일은 .생략되고, 이름이 로 시작하는 파일은 -옵션으로 해석되어 find혼란을 야기하므로 일반적으로 와 동일하지 않습니다 find . ….

/파일 이름의 일부로 " "로 끝나는 문자열이 없습니다.암시한다하지만 이것이 현재 디렉토리가 다음과 같다는 의미는 아닙니다.표시된빈 문자열(문자열이 없는 것과 동일하지는 않지만 인쇄할 때 동일하게 보일 수 있음)

답변3

일반적으로 빈 문자열은 쉘 명령이나 시스템 호출에서 현재 디렉토리를 나타내지 않습니다.일부 이전 시스템에서는 작동했지만 POSIX 호환 시스템에서는 작동하지 않았습니다..

때때로 빈 문자열을 전달하고 프로그램이 디렉토리 이름을 예상할 때 현재 디렉토리를 사용하는 프로그램을 찾을 수 있습니다. 이는 의도적인 경우도 있고, 주어진 문자열이 슬래시로 시작하지 않을 때 현재 디렉터리의 절대 경로 앞에 추가하는 부작용이 있는 경우도 있습니다.

당신에게 가장 좋은 것은 를 떠나는 것입니다 ./. 아무런 해를 끼치 지 않습니다.

파일 목록이 다음과 같은 경우

find . … | sed 's!^\./!!'

이로 인해 개행 문자가 포함된 일부 파일 이름이 손상됩니다. 이는 일반적으로 사람이 소비하는 데에는 문제가 되지 않으며 의 출력은 find모호하므로 프로그램 소비에 적합하지 않습니다. 프로그램 사용에 적합한 를 사용하는 경우 어쨌든 접두어 -print0에 신경 쓰지 않을 것입니다 ./.

find * …대신 사용할 수 있지만 일반적으로 부적합하게 만드는 여러 가지 결함이 있습니다 find . ….find *

  • .생략되어 있습니다.
  • 모든 도트 파일(또는 ..`으로 시작하는 파일 .)은 생략됩니다.
  • 현재 디렉터리에 이름이 시작하는 파일 이름(또는 or ... -이라는 파일 ) 이 있으면 에 의해 옵션이나 조건자로 해석됩니다 .!(find

필터가 현재 디렉터리를 제외하는 경우 첫 번째 사항은 중요하지 않습니다. 두 번째 점의 경우 패턴을 사용하여 ..?* .[!.]* *현재 디렉터리의 모든 파일과 일치할 수 있지만 각 패턴이 하나 이상의 파일과 일치하는지 확인하고 일치하지 않으면 생략해야 합니다. 이는 가능하지만 매우 번거롭습니다. 마지막 포인트는 스토퍼입니다. 따라서 find *빠른 명령줄 사용에 적합할 수 있지만 스크립트에서는 사용하지 마십시오.

대안적인 접근법은 쉘의 재귀적 글로빙 기능을 사용하는 것입니다.

printf '%s\n' **/*.h

shopt -s globstar이는 bash 및 ksh93에서 활성화해야 하며 set -o globstardash와 같은 기본 POSIX 셸에는 존재하지 않습니다. 도트 파일은 기본적으로 탐색되지 않습니다. 이를 포함하려면 먼저 globbing이 shopt -s dotglobbash 또는 FIGNORE='@(.|..)'ksh93의 도트 파일을 무시하지 않도록 만드세요. 또한 일치하는 항목이 없으면 이 명령은 패턴을 인쇄합니다. 대신 bash에서 실행하여 빈 줄을 인쇄하고 ksh에서 shopt -s nullglob패턴을 사용하세요 .~(N)**/*.h

zsh에서는 재귀적 글로빙이 기본적으로 켜져 있습니다. glob 한정자를 사용 D하여 도트 파일을 포함하고 N일치하는 항목이 없는 경우 빈 줄을 인쇄합니다(기본적으로 패턴이 파일과 일치하지 않으면 zsh에서 오류가 발생합니다). printf위와 같이 사용하거나

print -rl -- **/*.h(DN)

답변4

선행 없이 find의 출력을 얻는 데 사용할 수 있는 다양한 트릭이 있습니다 ./.

  1. find -printf옵션을 사용하여 print 만 하도록 지시하세요 %f. 보다 man find:

    %f 선행 디렉토리가 제거된 파일 이름입니다(마지막 요소만).

    예를 들어:

    find . -name "*.h" -printf "%f\n"
    
  2. 출력을 구문 분석합니다.

    find . -name "*.h" | sed 's#^./##'
    
  3. @Anthon의 트릭

    find * -name "*.h"
    

다른 질문의 경우 빈 문자열은 현재 디렉터리를 나타내지 않습니다. 다양한 프로그램이 현재 디렉터리를 기본값으로 사용하므로 인수 없이 프로그램을 실행하면 현재 디렉터리에서 실행됩니다.

관련 정보