입력 목록이 제공된 각 입력에 대해 명령을 실행하는 방법

입력 목록이 제공된 각 입력에 대해 명령을 실행하는 방법

여러 개의 폴더가 있고 각 폴더에 CD를 넣고 명령을 실행하고 싶습니다. 나는 이것이 다음과 같아야 한다고 생각합니다.

(다음은 제가 하고 싶은 일을 인위적으로 단순화한 예입니다.)

ls | xargs echo 'Looking at {}' && cd {} && /bin/do_stuff

그러나 이것은 작동하지 않습니다. 어떻게 해야 하나요?

답변1

xargs명령이 직접 실행되기 때문에 작동하지 않습니다 . 이는 한 줄의 셸 코드도 허용하지 않으며 실행을 위해 명령을 셸에 전달합니다. 사실, 이 모든 &&는 쉘에 의해 해석됩니다앞으로 ls달리는 것조차 xargs. 또한 은 {}이해하기 쉬운 구조 find입니다 xargs.

( 원하는 경우 -Iwith를 사용하여 xargs이 기능을 흉내낼 수 있습니다 find.)

가장 쉬운 방법 xargs은 명령을 쉘 스크립트에 넣는 것입니다.

#!/bin/sh
echo "Looking at $1"
cd $1
/bin/do_stuff

( 다른 하위 디렉터리만 포함하는 디렉터리에서 실행하는 한 실패하지 않을 것처럼 보이고 실패하지 않기 때문에 이를 실제로 대체했습니다. "and" 동작이 필요한 경우 스크립트에 필요한 수정 사항 은 명백 &&합니다 . .);echocd

그런 다음 쉘 스크립트를 실행하십시오 xargs. 당신이 그것을 호출하는 경우 dostuff.sh:

$ ls | xargs ./dostuff.sh

dostuff.sh처럼 실행 가능으로 표시되어야 합니다 chmod +x dostuff.sh.

아마도 이 모든 것을 한 줄에 쓸 수 있는 방법이 있을 것입니다 sh -c. 그러나 이런 일을 하는 마법을 기억하지 못한다면 그것은 대부분 단지 호기심일 뿐이지 않습니까?

답변2

xargs올바른 도구이지만 사용하기가 어렵습니다.

xargs당신이 지시하지 않는 한 쉘을 실행하지 마십시오. 옵션이 아닌 첫 번째 인수에 지정된 명령을 실행하고 명령줄에 추가 인수를 전달한 다음 표준 입력에서 읽은 인수를 전달합니다. 예를 들어

echo hello world | xargs echo 'Looking at'

달리다 echo 'Looking at' hello world. 입력 줄당 한 번씩 명령을 실행하려면 다음을 사용하십시오 xargs -L1.

(echo hello; echo world) | xargs -L1 echo 'Looking at'

쉘 명령을 실행 하려면 xargs명시적으로 쉘을 호출하도록 해야 합니다.

(echo hello; echo world) | xargs sh -c 'echo "Looking at $0" && cd "$0" && /bin/do_stuff'

(아니면 tcsh -c정말 하고 싶지만 지금은 21세기입니다.)

명령 내에서 보간법을 사용할 수 있지만 -I {}이는 입력에 셸 특수 문자가 포함되지 않은 경우에만 작동한다는 점에 유의하세요. {}입력을 명령( $0위)에 인수로 전달하는 이점은 입력에 대해 가정이 이루어지지 않는다는 것입니다(구문에 따라 줄로 구분되고 후행 공백을 포함하지 않는다는 점 제외 xargs -L).

Bourne/POSIX 스타일 셸에서 더 많은 라인을 사용하면서도 더 깔끔하게 만드는 또 다른 방법은 셸 내장 함수 주위에 루프를 사용하는 것입니다 read.

{ echo hello; echo world; } |
while IFS= read -r line; do
  echo "Looking at $line"
  (cd "$line" && /bin/do_stuff)
done

( cd전체 루프가 동일한 셸에서 실행되기 때문에 하위 셸에서 실행하고 있으며 해당 셸의 작업 디렉터리를 변경하고 싶지 않습니다.)

관련 정보