찾기로 찾은 파일을 인수로 전달하는 방법은 무엇입니까?


9

먼저 사소한하지만, 적용 할 답변 잘라 : 나는 둘 다 사용할 수 있습니다 find+의 xargs트릭도 (같은 그 변종 find과를 -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-print0sort-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한 번의 검색을 수행하면 다른 검색을 처리하는 방법이 여전히 남아 있습니다.

답변:


13

배열을 사용하십시오.

파일 이름에 줄 바꿈 가능성을 처리 할 필요가 없다면

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, 사용할 수있는 -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)

우수한! 배열에 대해 생각하고있었습니다. 그러나 어떻게 든 나는 그 mapfile(또는 그 동의어 readarray) 에서 아무것도 찾지 못했습니다 . 그러나 작동합니다!
Adam Badura

그러나 약간 향상시킬 수 있습니다. while루프가 있는 Bash <4.4 버전 (내가 가지고있는 ...) 은 배열을 지우지 않습니다. 이는 파일을 찾을 수없는 경우 배열이 정의되지 않았 음을 의미합니다. 이미 정의되어 있으면 이전 파일을 바꾸지 않고 새 파일이 추가됩니다. declare -a ABC_FILES='()';전에 추가 while하면 트릭이되는 것 같습니다 . (단지 추가 ABC_FILES='()';하지 않는 동안 )
Adam Badura

또한 < <여기서 의미하는 것은 무엇입니까? 와 같은 <<가요? <<구문 오류 ( "예기치 않은 토큰`( '") 를 생성 하도록 변경하는 것 같지는 않습니다 . 그래서 그것이 무엇이며 어떻게 작동합니까?
Adam Badura

또 다른 개선 사항 (내 특정 용도와 함께)은 또 다른 배열을 구성하는 것입니다. 그래서 우리는 그것들을 가지고 있습니다 ABC_FILES. 괜찮습니다. 그러나 비어 있거나 ABS_ARGS비어있는 배열 인 경우 비어있는 배열을 만드는 것도 유용합니다 . 나중에이 방법으로 나중에 다음 과 같이 사용할 수 있습니다 : 그룹 중 어느 것이 비어 있는지에 관계없이 올바르게 작동하는지 확인하십시오. 또는 다르게 말하면이 방법 (및 )은 실제 경로가 뒤에 오는 경우에만 제공됩니다. ABC_FILES('--abc-files' "${ABC_FILES[@]}")./program "${ABC_ARGS[@]}" "${XYZ_ARGS[@]}"--abc-files--xyz-files
Adam Badura

1
@AdamBadura : PROCESS SUBSTITUTION에 의해 생성 된 특수 파일에서 while read ... done < <(find blah)일반적인 쉘 리디렉션 <입니다 . 파이프 라인이 서브 쉘 에서 루프를 실행하여 파이프 라인에 설정된 var가 후속 명령에 대해 유지되지 않기 때문에 이는 파이프 와 다릅니다 . find blah | while read ... donewhile
dave_thompson_085

3

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 's answer에 대한 주석에서 추가 된 요청을 처리하지 않으며 --a가 비어 있으면 --afiles를 생략합니다.


Bash에서 이해하는 것처럼 강제 IFS로 나눌 수있는 방법이 null없습니까?
Adam Badura

@AdamBadura : 나는 확실하지 않다; bash는 IFS를 포함한 모든 변수에서 널 바이트를 허용하지 않습니다. (가) 참고 read -d ''steeldriver의 방법에서 사용하는 것은입니다 문자열 널 바이트를 포함하지 않는 하나. (그리고 어쨌든 명령 옵션은 var가 아닙니다.)
dave_thompson_085

또한 set -o noglobsplit + glob 연산자 (에서 제외)를 사용하기 전에 globbing ( )을 비활성화해야합니다 zsh.
Stéphane Chazelas


@AdamBadura 예는, 배쉬에서, 널 정확히과 동일 $'\0'하고 또한 ''.
Isaac Isaac

1

왜 당신이 포기했는지 이해가되지 않습니다 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

당신이 맞아요! 이것은 잘 작동합니다! 그러나 -print0두 번째로 놓친 것을 주목하십시오 find. 또한이 길을 가고 있다면 난을 둘 것 --abc-filesint로서 echo단지 일관성을 위해 -뿐만 아니라.
Adam Badura

이 접근 방식은 어레이 접근 방식보다 단순하고 다소 단순합니다. 그러나 .abc파일 이없는 경우 --abc-files(와 동일 .xyz) 없어야 하는 경우를 다루기 위해 추가 논리가 필요합니다 . 배열 기반 솔루션 으로 steeldriver은 또한 여분의 논리가 필요하지만 여기에 그리 하찮은이 솔루션의 주요 장점 파괴하는 반면 그 논리가 간단하다 - 단순.
Adam Badura

또한 확실하지는 않지만 , ( ), ( ) 또는 ( ) 인수 로 명시 적으로 지시 하지 않는xargs 한 인수를 분할 하지 않고 하나 대신 명령을 거의 만들지 않을 것이라고 가정합니다 . 내가 맞아? 아니면 몇 가지 기본값이 있습니까? 내 프로그램이 제대로 같은 분할을 처리 할 것이며, 나는 오히려 그것을 호출 실패 ... 것으로-L--max-lines-l--max-args-n--max-chars-s
아담 바두라

1
@AdamBadura Missing- -print0고마워요. 나는 모든 대답을 모르지만 내 솔루션으로 인해 추가 논리를 포함시키기가 어렵다는 데 동의합니다. 아마도이 접근법을 알면 아마도 배열을 직접 사용할 것입니다. 나의 대답은 당신을위한 것이 아닙니다. 다른 답변을 이미 수락했으며 문제가 해결되었다고 가정합니다. 방금 여러 소스에서 인수를 전달할 수 있음을 지적하고 싶었습니다 xargs. 개념 증명으로 취급 할 수 있습니다. 이제 우리는 서로 다른 접근법을 거의 알지 못하며 모든 경우에 적합한 것을 의식적으로 선택할 수 있습니다.
Kamil Maciorowski

예, 이미 어레이 기반 솔루션을 구현했으며 매력처럼 작동합니다. 나는 그것이 선택성을 다루는 것이 얼마나 깨끗한 지 특히 자랑스럽게 생각합니다 (파일이 없다면 no --abc-files). 그러나 당신은 옳습니다-당신의 대안을 아는 것이 좋습니다! 특히 나는 그것이 불가능하다고 생각했다.
Adam Badura
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.