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

이것이 당신이 원하는 것입니다. 화타이

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


유틸리티가 호출될 때마다 표준 입력에서 가져오는 최대 인수 수를 설정합니다.

이전 예제로 돌아가서, xargs매개변수 2개만 취하고 종료하려면 다음을 사용할 수 있습니다.@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

에코를 제거하고 기능이 실제로 작동하도록 만드세요.

관련 정보