
사소하지만 적용할 수 없는 답변을 먼저 잘라냅니다. 호출당 이러한 표현식을 거의 사용해야 하기 때문에 find
+ xargs
트릭이나 그 변형(예: find
with )을 사용할 수 없습니다. -exec
이에 대해서는 마지막에 다시 설명하겠습니다.
이제 더 나은 예를 들어 다음을 고려해 보겠습니다.
$ find -L some/dir -name \*.abc | sort
some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
이를 인수로 어떻게 전달합니까 program
?
그냥 하는 것만으로는 효과가 없지
$ ./program $(find -L some/dir -name \*.abc | sort)
program
다음 인수를 가져오므 로 실패합니다 .
[0]: ./program
[1]: some/dir/1.abc
[2]: some/dir/2.abc
[3]: some/dir/a
[4]: space.abc
볼 수 있듯이 공백이 있는 경로는 분할되었으며 program
이를 두 개의 다른 인수로 간주합니다.
작동할 때까지 견적
저와 같은 초보 사용자는 이러한 문제에 직면했을 때 마침내 작동할 때까지 무작위로 인용문을 추가하는 경향이 있는 것 같습니다. 여기서는 도움이 되지 않는 것 같습니다…
"$(…)"
$ ./program "$(find -L some/dir -name \*.abc | sort)"
[0]: ./program
[1]: some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
따옴표는 단어 분할을 방지하므로 모든 파일이 단일 인수로 전달됩니다.
개별 경로 인용
유망한 접근 방식:
$ ./program $(find -L some/dir -name \*.abc -printf '"%p"\n' | sort)
[1]: "some/dir/1.abc"
[2]: "some/dir/2.abc"
[3]: "some/dir/a
[4]: space.abc"
물론 따옴표가 있습니다. 그러나 더 이상 해석되지 않습니다. 그것들은 단지 문자열의 일부일 뿐입니다. 그래서 그들은 단어 분리를 막지 못했을 뿐만 아니라 논쟁까지 벌였습니다!
IFS 변경
그런 다음 IFS
. 나는 find
어쨌든 "유선 경로" 자체에 문제 가 없도록 -print0
선호 합니다 . 그렇다면 캐릭터에 단어 분할을 강요하여 모든 것을 갖추는 것은 어떨까요 ?sort
-z
null
$ ./program $(IFS=$'\0' find -L some/dir -name \*.abc -print0 | sort -z)
[0]: ./program
[1]: some/dir/1.abcsome/dir/2.abcsome/dir/a
[2]: space.abc
따라서 여전히 공간에서는 분할되고 null
.
나는 (위에 표시된 대로) 및 이전에 IFS
과제를 배치하려고 했습니다 . 또한 , 와 같은 다른 구문을 시도했습니다 . 둘 다 및 가 있거나 없는 것으로 인용되었습니다 . 그 어느 것도 아무런 차이가 없는 것 같았습니다…$(…)
./program
\0
\x0
\x00
'
"
$
그리고 여기에는 아이디어가 없습니다. 몇 가지를 더 시도했지만 모두 나열된 것과 동일한 문제가 발생하는 것 같았습니다.
내가 또 무엇을 할 수 있나요? 전혀 가능합니까?
물론, program
패턴을 받아들이고 검색 자체를 수행할 수 있습니다. 하지만 이를 특정 구문으로 수정하는 데는 이중 작업이 많이 필요합니다. (예를 들어 파일을 제공하는 것은 어떻습니까 grep
?)
program
또한 경로 목록이 포함된 파일을 허용 하도록 만들 수도 있습니다 . 그런 다음 일부 임시 파일에 표현식을 쉽게 덤프 find
하고 해당 파일에 대한 경로만 제공할 수 있습니다. 이는 사용자가 간단한 경로만 가지고 있는 경우 중간 파일 없이 제공될 수 있도록 직접 경로를 따라 지원될 수 있습니다. 그러나 이는 좋지 않은 것 같습니다. 추가 구현이 필요한 것은 말할 것도 없고 추가 파일을 생성하고 관리해야 합니다. (그러나 장점으로는 인수인 파일 수가 명령줄 길이에 문제를 일으키기 시작하는 경우에 대한 구제책이 될 수 있습니다…)
마지막으로 내 경우에는 find
+ xargs
(및 유사) 트릭이 작동하지 않는다는 점을 다시 한 번 상기시켜 드리겠습니다. 설명을 단순화하기 위해 하나의 인수만 표시합니다. 하지만 내 실제 사례는 다음과 같습니다.
$ ABC_FILES=$(find -L some/dir -name \*.abc | sort)
$ XYZ_FILES=$(find -L other/dir -name \*.xyz | sort)
$ ./program --abc-files $ABC_FILES --xyz-files $XYZ_FILES
따라서 xargs
하나의 검색을 수행하면 여전히 다른 검색을 처리하는 방법이 남습니다…
답변1
배열을 사용하세요.
파일 이름에 개행 가능성을 처리할 필요가 없다면 다음과 같이 하면 됩니다.
mapfile -t ABC_FILES < <(find -L some/dir -name \*.abc | sort)
mapfile -t XYZ_FILES < <(find -L other/dir -name \*.xyz | sort)
그 다음에
./program --abc-files "${ABC_FILES[@]}" --xyz-files "${XYZ_FILES[@]}"
만약 너라면하다파일 이름 내에서 줄 바꿈을 처리해야 하고 bash >= 4.4인 경우 배열 구성 중에 이름을 null로 종료 -print0
하고 사용할 수 있습니다.-d ''
mapfile -td '' ABC_FILES < <(find -L some/dir -name \*.abc -print0 | sort -z)
(그리고 마찬가지로 XYZ_FILES
). 만약 너라면~하지 않다최신 bash가 있으면 null로 끝나는 읽기 루프를 사용하여 파일 이름을 배열에 추가할 수 있습니다.
ABC_FILES=()
while IFS= read -rd '' f; do ABC_FILES+=( "$f" ); done < <(find -L some/dir -name \*.abc -print0 | sort -z)
답변2
IFS=newline을 사용할 수 있지만(파일 이름에 개행 문자가 포함되어 있지 않다고 가정) 대체하기 전에 외부 쉘에서 이를 설정해야 합니다.
$ ls -1
a file with spaces
able
alpha
baker
boo hoo hoo
bravo
$ # note semicolon here; it's not enough to be in the environment passed
$ # to printf, it must be in the environment OF THE SHELL WHILE PARSING
$ IFS=$'\n'; printf '%s\n' --afiles $(find . -name 'a*') --bfiles $(find . -name 'b*')
--afiles
./able
./a file with spaces
./alpha
--bfiles
./bravo
./boo hoo hoo
./baker
zsh
하지만 그렇지 않은 경우 에는 null 도 bash
사용할 수 있습니다 . 다음과 같이 전혀 사용되지 않는 충분히 이상한 문자가 하나 있는 경우 $'\0'
에도 개행 문자를 처리할 수 있습니다.bash
IFS=$'\1'; ... $(find ... -print0 | tr '\0' '\1') ...
그러나 이 접근 방식은 find a가 비어 있는 경우 --afiles를 생략하라는 @steeldriver의 답변에 대한 의견에서 작성한 추가 요청을 처리하지 않습니다.
답변3
왜 포기했는지 잘 모르겠습니다 xargs
.
따라서
xargs
하나의 검색을 수행하면 여전히 다른 검색을 처리하는 방법이 남습니다…
문자열은 --xyz-files
많은 인수 중 하나일 뿐이며 프로그램에서 해석되기 전에 이를 특별하다고 생각할 이유가 없습니다. 두 결과 xargs
중 하나 를 통과할 수 있다고 생각합니다 .find
{ find -L some/dir -name \*.abc -print0 | sort -z; echo -ne "--xyz-files\0"; find -L other/dir -name \*.xyz -print0 | sort -z; } | xargs -0 ./program --abc-files