이렇게만 하면 문제가 해결되지 않습니다

이렇게만 하면 문제가 해결되지 않습니다

먼저 사소하지만 적용할 수 없는 답변을 잘라냅니다. 호출당 이러한 표현식을 거의 사용해야 하기 때문에 find+ xargs트릭이나 그 변형(예: findwith )을 사용할 수 없습니다 . -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. 어쨌든 나는 "유선 경로"자체에서 문제를 일으키지 않도록 findwith -print0sortwith - 를 선호합니다. 그렇다면 역할 분할을 강제하여 모든 것을 갖추는 것은 -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.

나는 (위와 같이) IFSbefore와 before에 과제를 넣어 보았습니다 . 나는 또한 with , with ,without과 같은 다른 구문을 시도했습니다 . 이들 중 어느 것도 아무런 차이가 없는 것 같습니다.$(…)./program\0\x0\x00'"$


이제 아이디어가 없어졌습니다. 몇 가지를 더 시도했지만 모두 동일한 문제가 나열된 것 같습니다.

내가 또 무엇을 할 수 있나요? 이것이 가능한가?

물론 program수락 모드를 만들어 직접 검색할 수도 있습니다. 하지만 이를 특정 구문으로 수정하는 동안 많은 이중 작업이 필요합니다. ( grep예를 들어 a를 통해 파일을 제공하는 것은 어떻습니까?)

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

null을 사용 zsh하지만 사용하지 않는 것도 bash가능합니다. 개행 문자를 처리할 수 $'\0'있다고 해도 bash이렇게 한 번도 사용되지 않은 이상한 문자가 있다면

 IFS=$'\1'; ... $(find ... -print0 | tr '\0' '\1') ...

그러나 이 방법은 @steeldriver의 답변에 대한 의견에서 작성한 추가 요청, 즉 find a가 비어 있는 경우 --afiles를 생략하는 추가 요청을 처리할 수 없습니다.

답변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

관련 정보