STDIN의 라인을 반복하고 쉘 명령을 실행하려면 어떻게 해야 합니까?

STDIN의 라인을 반복하고 쉘 명령을 실행하려면 어떻게 해야 합니까?

STDIN에서 가져온 각 줄에 대해 쉘 명령을 실행하고 싶습니다.

이 경우에는 xargs mv. 예를 들어, 다음 두 줄이 주어집니다.

mfoo foo
mbar bar

나는 다음을 실행하고 싶습니다 :

xargs mv mfoo foo
xargs mv mbar bar

ruby나는 , awk및 를 사용하여 다음 전략을 시도했습니다 xargs. 그러나 나는 잘못하고 있습니다.

단지 xargs:

$ echo "mbar bar\nmbaz baz" | xargs mv
usage: mv [-f | -i | -n] [-v] source target
       mv [-f | -i | -n] [-v] source ... directory

을 통해 awk:

$ echo "mbar bar\nmbaz baz" | awk '{ system("xargs $0") }'

을 통해 ruby:

$ echo "mbar bar\nmbaz baz" | ruby -ne '`xargs mv`'
$ ls
cat  foo  mbar mbaz

질문이 몇 개 있습니다:

  • 내가 하려는 일을 어떻게 해야 하나요?
  • 내 시도마다 어떤 문제가 있습니까?
  • 내가 하려는 일에 대해 "생각"하는 더 좋은 방법이 있습니까?

xargs특히 다음이 작동하기 때문에 내 시도가 작동하지 않는다는 사실이 혼란스럽습니다 .

$ echo "foo\nbar" | xargs touch
$ ls
bar foo

답변1

echo "mbar bar\nmbaz baz" | xargs mv

무슨 일이 일어나고 있는지 확인하려면 옵션 xargs을 사용해야합니다 . 따라서 위의 경우 에서 를 -t호출하면 다음과 같은 내용이 표시됩니다.xargs-t

mv mbar bar mbaz baz

그러니 당연히 옳지 않습니다. 배고픈 악어 처럼 xargs파이프를 통해 공급되는 모든 인수를 먹었습니다 echo. 따라서 croc에 대한 인수 릴리스를 제한하는 방법이 필요합니다. 그리고 라인별로 요청했으므로 필요한 것은 -l또는 -Lfor POSIX 옵션입니다.

echo "mbar bar\nmbaz baz" | xargs -l -t mv

POSIX 방식:

echo "mbar bar\nmbaz baz" | xargs -L 1 -t mv

mv mbar bar
mv mbaz baz

그리고 이것이 당신이 원했던 것입니다. HTH

답변2

이 방법으로 갈 수 있습니다 :

echo -e "foo bar\ndoo dar" | xargs -n 2 mv

파일에서 읽으려면:

cat lines.txt | xargs -n 2 mv

또는

xargs -a lines.txt -n 2 mv

답변3

xargs예상대로 동작하지 않을 수도 있습니다. 이 질문에 대한 @MichaelHomer의 의견을 참조하십시오.

xargs mv mfoo foo입력을 기다리고 입력되는 mfoo foo $x_1 $x_2 $x_3...모든 줄에 대해 mv를 실행합니다. $x_n@마이클호머

이는 본문을 읽어보면 확인할 수 있습니다.xargs매뉴얼 페이지:

설명
xargs 유틸리티는 표준 입력에서 공백, 탭, 개행 및 파일 끝으로 구분된 문자열을 읽고 해당 문자열을 인수로 사용하여 유틸리티를 실행합니다.

실제로는 xargs첫 번째 인수로 지정된 명령줄 유틸리티에 인수를 공급할 때 줄바꿈을 무시하는 것처럼 보입니다. 예를 들어 개행 문자에 어떤 일이 발생하는지 확인하세요.

$ echo "foo bar\ncat dog"
foo bar
cat dog
$ echo "foo bar\ncat dog" | xargs echo
foo bar cat dog

이 동작은 다음을 사용하여 제어할 수 있습니다.-n깃발:

-n 숫자


각 유틸리티 호출 에 대해 표준 입력에서 가져온 최대 인수 수를 설정합니다 .

이전 예제로 돌아가서 xargs2개의 인수만 취하고 종료하면 다음을 사용할 수 있습니다.@ddnomad의 접근 방식:

$ echo "foo bar\ncat dog" | xargs -n 2 echo
foo bar
cat dog

또한 Rakesh Sharma의 답변에 있는 주석에서 볼 수 있듯이 BSD에서는 xargs플래그를 사용하여 읽을 줄 수를 지정할 수 있습니다 -L. 매뉴얼 페이지에서:

-L 번호

읽은 모든 숫자 행에 대해 유틸리티를 호출합니다. EOF에 도달하고
숫자보다 적은 행을 읽은 경우 사용 가능한 행으로 유틸리티가 호출됩니다.

테스트에도 마찬가지로 유용한 스위치는 -t다음과 같습니다.

예제를 다시 살펴보면 다음 두 가지가 모두 작동합니다. 그러나 두 번째 예는 이 경우 의도한 것이기 때문에 더 좋습니다.

$ echo "foo bar\ncat dog" | xargs -n 2 echo
foo bar
cat dog
$ echo "foo bar\ncat dog" | xargs -L 1 echo
foo bar
cat dog

매뉴얼 페이지의 참고 사항:

-L 및 -n 옵션은 상호 배타적입니다. 마지막으로 주어진 것이 사용됩니다.

답변4

xargs를 사용하지 않는 매우 간단한 솔루션이 있습니다.
이 함수를 정의하십시오:

$ mv2() { while (($# >1 )); do echo mv "$1" "$2"; shift 2; done; }

그런 다음 필요한 파일 이름 목록을 사용하여 호출하세요(줄 바꿈 필요 없음).

$ mv2 mbar bar mbaz baz
mv mbar bar
mv mbaz baz

기능이 실제로 작동하도록 하려면 에코를 제거하십시오.

관련 정보