ls
프로세스 대체를 사용하여 파일 목록(예: 또는 에서 생성됨 find
)을 특정 응용 프로그램으로 열어서 보거나 보고 싶습니다 . 이러한 목록을 파이핑하는 것은 xargs
스크립트나 바이너리에 대해 작동 하지만 xargs
개체가 셸 별칭인 경우에는 실패합니다.이 사이트에 대한 기타 질문. [내가 염두에 두고 있는 구체적인 응용 프로그램은 다음과 같습니다 feh
.]
xargs
bash 별칭의 이러한 제한을 고려하여 대신 을 사용해 보았습니다 . [script/binary/alias] <(find . -iname '*')
이 구성 은 모두 원하는 효과를 생성하지만 입력(파일 경로 목록)이 대신 열기/보기를 위해 애플리케이션(예: , . 프로세스 대체 문의 수신자가 되는 특정 경우 에 이 실패에 수반되는 오류는 " "입니다. 프로세스 대체 문 앞에 입력 리디렉션 연산자를 추가해도 문제가 완화되지 않습니다(예: 다른 명령의 경우와는 다름 ).cat
less
<
feh
gimp
feh
feh: No loadable images specified.
less
따라서 내 질문은 명시된 목적(예: 파일 목록 열기)에 프로세스 대체를 사용할 수 있는지 여부와 그렇다면 적절한 구문이 무엇인지에 관한 것입니다. bash 별칭과의 호환성을 위한 특정 요구 사항( ~/.bash_aliases
또는 유사한 구성 파일에 지정됨)
답변1
명령이 파이프를 통해 내용을 읽는 대신 여러 파일을 인수로 허용하는 경우 간단한 명령 대체가 작동합니다.
[script/binary/alias] $(find .)
또는 명령이 한 번에 하나의 파일만 허용하는 경우 for 루프가 트릭을 수행해야 합니다.
for file in $(find .); do [script/binary/alias] "$file"; done
두 경우 모두 공백, 탭, 줄 바꿈, 와일드카드가 포함된 파일 이름은 문제를 일으킬 수 있으며 while/read 루프는 이를 처리할 수 있습니다.
find . | while IFS= read -r file; do [script/binary/alias] "$file"; done
개행 문자가 포함된 파일 이름은 여전히 문제를 일으킬 수 있습니다. find
0으로 구분된 출력으로 문제가 해결됩니다(이 경우 bash
, zsh
, 로 가정 ksh
).
find . -print0 | while IFS= read -rd '' file; do [script/binary/alias] "$file"; done
이러한 모든 예에서 find . -type f
일반 파일만 처리하려는 경우 더 적절할 수 있습니다.
답변2
나중에 별칭을 확장하려면 xargs
다음을 수행하세요.
alias xargs='xargs '
그러나 첫 번째 단어만 xargs
별칭 확장의 영향을 받습니다. 이는 표준 명령에 대한 별칭이 있는 경우 의도하지 않은 영향을 미칠 수 있습니다.
$ alias xargs='xargs ' a='echo test'
$ set -x
$ echo x | xargs a
+ echo x
+ xargs echo test
test x
$ echo x | xargs -r a
+ echo x
+ xargs -r a
xargs: a: No such file or directory
별칭에 다른 이름을 지정하고 보다 합리적인 기본 동작을 사용할 수도 있습니다 xargs
. GNU를 예로 들어보겠습니다 xargs
.
alias axargs='xargs -r -d "\n" '
<(...)
이제 프로세스 대체가 단일 매개변수, 즉 명령 출력(라이브 스트림)을 포함하는 파일 이름으로 확장됩니다.
출력의 경우 find
이는 개행으로 구분된 파일 목록을 포함할 것으로 예상되는 파일 이름을 인수로 허용하는 명령에만 유용합니다.
feh
중 하나이다:
feh -f <(find . -mtime -1 -type f -name '*.jpg')
이는 파일 이름에 개행 문자가 포함되지 않은 경우에만 작동합니다.
GNU 구현에는 파일 이름 목록을 안정적으로 전달할 수 있도록 ( or) 옵션과 결합된 파일에서 인수 목록을 가져오는 옵션이 xargs
있습니다 .-a
-0
-print0
-exec printf '%s\0' {} +
find
xargs -r0a <(find ... -print0) feh....
하지만 이는 앨리어싱 문제를 해결하는 데 도움이 되지 않습니다.
이제 명령의 출력을 다른 명령의 인수로 전달하려면 다음을 사용할 수 있습니다.주문하다대신에 대체하다프로세스치환. 하지만 몇 가지 주의사항에 유의하시기 바랍니다.
cmdA "$(cmdB)"
후행 개행 문자 없이 의 출력을 cmdB
인수로 전달합니다 cmdA
. 예를 들어, 3개의 일반 파일(여기서는 특이하지만 완벽하게 유효한 이름) 이 있는 경우 * * /etc/passwd .jpg
, foo.txt
및 <nl><nl>
( <nl>
개행 문자를 나타냄) 의 출력 은 이므로 인수를 받습니다 .find . -type f
cmdB
./* * /etc/passwd .jpg<nl>./foo.txt<nl>./<nl><nl><nl>
cmdA
./* * /etc/passwd .jpg<nl>./foo.txt<nl>./
이것은 당신이 원하는 것이 아닐 수도 있습니다. cmdA
각 파일 이름을 별도의 인수( ./* * /etc/passwd
, ./foo.txt
및 ) 로 받고 싶습니다 ./<nl><nl>
.
따라서 기본적으로 출력을 별도의 파일 이름으로 분할해야 합니다 find
. POSIX 쉘에는 하나의 연산자가 있습니다.분할+전역떠날 때 암시적으로 호출되는 연산자명령 대체(또는 매개변수 확장 또는 산술 확장) 따옴표 없이.
cmdA $(cmdB)
cmdB
출력은 후행 줄 바꿈 없이 문자(기본값은 공백, 탭 및 줄 바꿈)로 분할되며 $IFS
각 단어는 와일드카드로 표시됩니다.
위의 예에서는 이것이 우리가 원하는 것이 아닙니다. 이는 ./* * /etc/passwd .jpg
, ./*
및 *
으로 구분되며 현재 디렉터리의 파일 목록에 와일드카드로 /etc/passwd
표시 됩니다 .jpg
../*
*
우리가 원하는 것은 개행 문자로 분할하고 와일드카드 부분을 수행하지 않는 것입니다. 이는 다음을 통해 수행됩니다.
IFS='
' # newline only
set -f
cmdA $(cmdB)
개행 문자가 포함된 파일 이름에는 여전히 작동하지 않습니다. 개행 문자가 포함된 파일 이름이 없음을 사용하거나 보장할 수 없는 경우 일반적으로 의 출력은 find
사후 처리가 불가능합니다 .-print0
이제 zsh
분할 \0
문자만 허용됩니다.
cmdA ${(0)"$(cmdB)"}
"$(cmdB)"
분할은 NUL 문자 시퀀스를 기반으로 합니다 . 또는:
IFS=$'\0' # no need for set -f in zsh
cmdA $(cmdB)
명령 대체 접근 방식의 또 다른 문제점은 cmdB
실패하거나 아무것도 출력하지 않으면 cmdA
인수 없이 계속 실행된다는 것입니다. 다음 구문을 사용하면 이를 방지하고 계속 사용할 수 있습니다 zsh
.
cmdA ${$(find...):?no file}
하지만 사용하면 대부분의 기능이 내부적으로 지원되므로 zsh
일반적으로 모든 문제를 해결할 필요가 없습니다 . 예를 들어 다음을 사용할 수 있습니다.zsh
find
myalias ./**/*.jpg(.m-1)
jpg
지난 24시간 동안 마지막으로 수정된 파일을 표시합니다 .