문서 내용 filelist
:
/some/path/*.txt
/other/path/*.dat
/third/path/example.doc
나는 이 파일들을 나열하고 싶기 때문에 다음과 같이 합니다:
cat filelist | xargs ls
그러나 이러한 범위를 확장하는 대신 다음과 같은 결과를 얻습니다.
ls: cannot access '/some/path/*.txt': No such file or directory ls: cannot access '/other/path/*.dat': No such file or directory /third/path/example.doc
답변1
껍질은 구를 확장합니다. 여기서는 매우 드문 경우입니다. Bourne과 유사한 셸(zsh 제외)에서는 인용되지 않은 명령 대체 시 암시적 분할+glob 연산자를 호출하는 것이 유용할 수 있습니다.
IFS='
' # split on newline only
set +o noglob # make sure globbing is not disabled
ls -ld -- $(cat filelist) # split+glob
에서는 zsh
다음을 수행합니다.
ls -ld -- ${(f)~"$(<filelist)"}
f
개행 문자로 분할된 매개변수 확장 플래그는 어디에 있습니까?~
필요하다매개변수 확장이나 명령 대체 시에는 기본적으로 와일드카드가 수행되지 않습니다.
일치하는 파일 목록이 크면 다음과 같은 문제가 발생할 수 있습니다.매개변수 목록이 너무 깁니다.버그(대부분의 시스템에서 시스템 호출의 제한 execve()
), xargs
그렇지 않으면 해결될 수 있습니다. 에서는 zsh
다음을 사용할 수 있습니다 zargs
.
autoload zargs
zargs --eof= -- ${(f)~"$(<filelist)"} '' ls -ld --
필요한 경우 제한을 피하기 위해 목록이 분할되어 여러 번 실행 zargs
됩니다 .ls
xargs
또는 목록을 내장 명령에 전달할 수 있습니다(따라서 시스템 execve()
호출이 필요하지 않음).
파일 목록만 인쇄:
print -rC1 -- ${(f)~"$(<filelist)"}
또는 xargs
NUL로 구분하여 입력하세요.
print -rNC1 -- ${(f)~"$(<filelist)"} |
xargs -r0 ls -ld --
파일과 일치하지 않는 glob이 있으면 zsh
오류 메시지가 표시됩니다. 이러한 glob을 아무것도 확장하지 않으려면 N
glob 한정자를 glob에 추가할 수 있습니다(이는 nullglob
glob별로 활성화됩니다).
print -rNC1 -- ${(f)^~"$(<filelist)"}(N) |
xargs -r0 ls -ld --
이 작업을 추가하면 glob 연산자가 없는 모든 행이 glob으로 변환되므로 경로에서 참조하는 파일과 존재하지 않는 파일이 필터링됩니다. 즉, Express as를 전달 하고 이 옵션을 활성화하지 않으면 (N)
glob 한정자를 사용할 수 없습니다. . 또한 한정자는 임의의 코드를 실행할 수 있으므로 파일 내용이 신뢰할 수 있는 소스에서 나오는 것이 중요합니다.filelist
(#q...)
extendedglob
filelist
Glob 을 포함한 다른 Bourne 유사 쉘에서는 bash
일치하지 않는 glob은 변경되지 않은 채로 남아 있으므로 문자 그대로 ls
해당 파일이 존재하지 않는다고 보고할 수 있는 오류로 전달됩니다.
에서는 bash
이 옵션(zsh에서 복사)을 사용 nullglob
하고 구체적으로 일치하는 glob이 없는 경우를 처리할 수 있습니다.
shopt -s nullglob
IFS=$'\n'
set +o noglob
set -- $(<filelist)
(( $# == 0 )) || printf '%s\0' "$@" | xargs -r0 ls -ld --
bash
zsh
, glob 한정자와 동등한 것이 없습니다 . glob 연산자가 없는 행(예: yours /third/path/example.doc
)이 glob으로 처리되고 실제 파일과 일치하지 않는 경우 제거되도록 하려면 @()
이러한 행에 추가할 수 있습니다(필수 extglob
). 그러나 이는 문자로 끝나는 줄에서는 작동하지 않습니다 /
. 그러나 @()
마지막 비문자에 추가하고 항상 있다는 /
사실 에 의존할 수 있습니다./
shopt -s nullglob extglob
IFS=$'\n'
set +o noglob
set -- $(LC_ALL=C sed 's|.*[^/]|&@()|' filelist)
(( $# == 0 )) || printf '%s\0' "$@" | xargs -r0 ls -ld --
그럼에도 불구하고 지원되는 glob 연산자 목록은 셸마다 크게 다릅니다. 그러나 귀하의 예( )에서 사용하는 유일한 것은 *
모든 사람이 지원해야 합니다.
답변2
스크립트를 약간 수정하고 sh
다음에서 호출할 수 있습니다 xargs
.
cat filelist | xargs -i -- /bin/sh -c 'ls $1' _X_ {}
xargs
아니면 파일 자체를 읽어 보겠습니다 .
xargs -a filelist -i -- /bin/sh -c 'ls $1' _X_ {}
답변3
while read filepattern
do
ls $filepattern
done < filelist
이 경우 파일 글로빙을 통해 변수 값을 확장하고자 하므로 따옴표 없이 변수를 사용해야 합니다.
/some/path/*.txt
쉘은 일치하는 파일 목록으로 대체됩니다 .
원하지 않는 파일 이름만 나열하려는 경우 ls
. echo
다음과 같은 것을 사용할 수 있습니다 echo $filepattern
.
위의 코드와는 달리 따옴표를 사용하면 질문 예제와 동일한 오류가 발생합니다. 왜냐하면 쉘이 /some/path/*.txt
to 와 같이 변경되지 않은 문자열을 전달하기 때문입니다 ls
.
while read filepattern
do
ls "$filepattern"
done < filelist