파이프 입력 라인 당 한 번 명령을 실행 하시겠습니까?


162

의 모든 일치에 대해 Java 명령을 한 번 실행하고 싶습니다 ls | grep pattern -. 이 경우, 나는 할 수 있다고 생각 find pattern -exec java MyProg '{}' \;하지만 일반적인 경우에 대해 궁금합니다. "모든 표준 입력 라인마다 한 번 명령을 실행하십시오"라고 말하는 쉬운 방법이 있습니까? (물고기 나 배쉬)

답변:


91

그게 뭐야 xargs.

... | xargs command

25
좀 빠지는. printf "foo bar\nbaz bat" | xargs echo whee생산할 것이다 whee foo bar baz bat. -L또는 -n옵션을 추가 하시겠습니까?
Jander

3
@Jander 질문은 다소 일반적이어서 일반적인 도구를 제공했습니다. 사실, 특정 상황에 따라 옵션으로 동작을 조정해야합니다.
Keith

4
... | tr '\ n' '\ 0'| xargs -0
vrdhn

7
"질문에 대한 정답을 제공하는 특정 상황"과 같이 말입니다. :)
mattdm

7
xargs 로이 작업을 수행하는 올바른 방법을 보려면 아래 내 답변을 참조하십시오.
Michael Goldshteyn 2016 년

167

받아 들여진 대답 은 옳은 생각이지만, 열쇠는 스위치 를 통과 xargs시키는 것 -n1입니다. "출력 라인 당 한 번 명령을 실행합니다":

cat file... | xargs -n1 command

또는 단일 입력 파일의 경우 파이프를 cat완전히 피하고 다음을 수행 할 수 있습니다 .

<file xargs -n1 command

1
비어있는 경우 실행할 xargs없는 기능도 있습니다 stdin. --no-run-if-empty -r: 표준 입력에 공백이없는 경우 명령을 실행하지 마십시오. 일반적으로 입력이 없어도 명령이 한 번 실행됩니다. 이 옵션은 GNU 확장입니다.
Ronan Jouchet

4
내부 회선에 어떻게 액세스 command합니까?
BT

이것은 xargs의 올바른 사용입니다. -n1이 없으면 매개 변수 목록을 모두 호출하지 않는 여러 호출로 처리하는 명령에서만 작동합니다.
masterxilo

3
printf "foo bar \ nbaz 박쥐"| xargs를 -n1 에코 휘잉 단어로하지 라인에 의해 분할
Gismo Ranas

112

Bash 또는 다른 Bourne 스타일 쉘 (ash, ksh, zsh 등) :

while read -r line; do command "$line"; done

read -r표준 입력에서 한 줄을 읽습니다 (역 슬래시 read-r해석하지 않으면 원하지 않습니다). 따라서 다음 중 하나를 수행 할 수 있습니다.

$ command | while read -r line; do command "$line"; done  

$ while read -r line; do command "$line"; done <file

6
내가 시도했을 때 tail -f syslog | grep -e something -e somethingelse| while read line; do echo $line; done작동하지 않았다. while루프 로 파이프 된 파일로 작업하고 tail -f,로만 작업하고으로 만 작업 grep했지만 두 파이프 모두 에서 작동 하지는 않았습니다. 주는 일 옵션은 그것을 작업했다grep--line-buffered

이것은 또한 각 라인을 stdin으로 보내야 할 때도 작동합니다 :command | while read -r line; do echo "$line" | command ; done
Den

21

Keith에게 동의합니다. xargs는 작업을위한 가장 일반적인 도구입니다.

나는 보통 3 단계 접근법을 사용합니다.

  • 작업하고 싶은 것이 생길 때까지 기본 작업을 수행하십시오.
  • 올바른 구문을 얻도록 awk로 줄을 준비하십시오.
  • 그런 다음 xargs가 bash의 도움으로 실행하도록하십시오.

더 작고 빠른 방법이 있지만이 방법은 거의 항상 작동합니다.

간단한 예 :

ls | 
grep xls | 
awk '{print "MyJavaProg --arg1 42 --arg2 "$1"\0"}' | 
xargs -0 bash -c

첫 번째 두 줄은 작업 할 파일을 선택한 다음 awk는 실행할 명령과 일부 인수를 사용하여 멋진 문자열을 준비하고 $ 1은 파이프의 첫 번째 열 입력입니다. 마지막으로 xargs 가이 문자열을 bash로 보내어 실행시킵니다.

약간 과잉이지만이 레시피는 매우 유연하기 때문에 많은 곳에서 도움이되었습니다.


6
참고, xargs -0그래서 당신의 AWK 인쇄 문이 있어야 레코드 구분자로 널 바이트를 사용합니다printf("MyJavaProg --args \"%s\"\0",$1)
글렌 잭맨에게

@glenn : null 문자를 놓치면 답이 업데이트됩니다.
Johan

@Johan은 큰 문제는 아니지만 사용 awk하는 경우 패턴 일치를 수행하고 grep 예를 건너 뛸 수 있습니다 .ls | awk '/xls/ {print...
Eric Renouf

15

이런 종류의 작업을 위해 GNU Parallel이 만들어졌습니다. 가장 간단한 사용법은 다음과 같습니다.

cat stuff | grep pattern | parallel java MyProg

자세한 내용은 소개 동영상을 참조하십시오 . http://www.youtube.com/watch?v=OpaiGYxkSuQ


1
파일을 직접 읽을 수 cat있기 때문에 여기에 대한 실제 필요가 없습니다grep
Eric Renouf


1
링크에 감사드립니다, 나는 그것이 더 읽기 쉽다는 것에 동의하지는 않지만, 그것이 그것이 관계없이 고려되었다는 것을 알면 좋을 것입니다. 대안이 실제로는 < stuff grep pattern아니지만 grep pattern stuff리디렉션이나 고양이가 전혀 필요 하지 않기 때문에 링크가 실제로 여기에 적용되지 않는다는 것을 약간 당황스럽게 합니다. 그럼에도 불구하고 그 주장이 실질적으로 변하지는 않으며으로 시작하는 파이프에서 항상 물건을 사용하는 것이 더 명확하다고 생각되면 당신에게 cat힘을
실어

8

또한 while read생선 껍질을 반복하십시오 ( 꼬리표 를 사용한다고 가정하면 생선 껍질을 원한다고 가정합니다 ).

command | while read line
    command $line
end

참고할 점이 거의 없습니다.

  • read-r가장 일반적인 사용 사례를 쉽게 만들기 위해 인수를 사용하지 않으며 백 슬래시를 해석하지 않습니다.
  • $linebash와 달리 물고기는 변수를 공백으로 분리하지 않으므로 인용 할 필요 가 없습니다.
  • command그 자체로는 구문 오류가 있습니다 (자리 표시 자 인수의 이러한 사용을 잡기 위해). 실제 명령으로 바꾸십시오.

? 대신 & while와 (을) 페어링 할 필요 는 없습니다 . dodoneend
aff

@aff 이것은 구체적으로 다른 구문을 가진 생선 껍질에 관한 것입니다.
Konrad Borowski

아, 그래서 그건 무슨 생선을 의미합니다.
aff

6

입력 인수가 명령 행에 정확히 삽입되는 위치를 제어해야하거나 여러 번 반복해야하는 경우을 사용해야 xargs -I{}합니다.

실시 예 # 1

another_folder현재 디렉토리의 하위 폴더를 미러링 하는 빈 폴더 구조를 만듭니다 .

    ls -1d ./*/ | xargs -I{} mkdir another_folder/{}
실시 예 # 2

stdin에서 온 파일 목록에 작업을 적용하십시오.이 경우 확장자 .html를 추가하여 각 파일을 복사 하십시오 .bak.

    find . -iname "*.html" | xargs -I{} cp {} {}.bak

로부터 xargs맥 OS / BSD에 대한 man 페이지 :

 -I replstr
         Execute utility for each input line, replacing one or more occurrences of
         replstr in up to replacements (or 5 if no -R flag is specified) arguments
         to utility with the entire line of input.  The resulting arguments, after
         replacement is done, will not be allowed to grow beyond 255 bytes; this is
         implemented by concatenating as much of the argument containing replstr as
         possible, to the constructed arguments to utility, up to 255 bytes.  The
         255 byte limit does not apply to arguments to utility which do not contain
         replstr, and furthermore, no replacement will be done on utility itself.
         Implies -x.

리눅스 xargs매뉴얼 페이지 :

   -I replace-str
          Replace  occurrences of replace-str in the initial-
          arguments with names read from standard input.  Al
          so,  unquoted  blanks do not terminate input items;
          instead the separator  is  the  newline  character.
          Implies -x and -L 1.

1

잠재적으로 위생 처리되지 않은 입력을 처리 할 때, 전체 작업을 실행하기 전에 (특히 사람들의 우편함 청소와 같은 파괴적인 경우) 육안 검사를 위해 한 줄씩 '맞춤법'을보고 싶습니다.

그래서 내가하는 일은 매개 변수 목록 (즉, 사용자 이름)을 생성하고 다음과 같이 한 줄에 하나씩 레코드로 파일에 공급하는 것입니다.

johndoe  
jamessmith  
janebrown  

그런 다음 목록을 열고 다음 vim과 같이 실행 해야하는 전체 명령 목록을 얻을 때까지 검색 및 바꾸기 식으로 맹 글링합니다.

/bin/rm -fr /home/johndoe  
/bin/rm -fr /home/jamessmith 

이런 식으로 정규 표현식이 불완전한 경우 어떤 명령에서 잠재적 인 문제가 있는지 알 수 있습니다 (예 :) /bin/rm -fr johnnyo connor. 이렇게하면 정규식을 취소하고보다 안정적인 버전으로 다시 시도 할 수 있습니다. 이름 맹 글링은 Van Gogh, O'Connors, St. Clair, Smith-Wesson과 같은 모든 에지 케이스를 처리하기가 어렵 기 때문에 악명 높은 것으로 유명합니다.

를 사용 하면 모든 일치 항목이 강조 표시되므로 의도하지 않은 방식으로 일치하거나 의도하지 않은 방식으로 쉽게 일치 할 수 있으므로이 set hlsearch작업을 수행하는 데 유용합니다 vim.

정규 표현식이 완벽하고 테스트 / 생각할 수있는 모든 사례를 포착하면 일반적으로 sed 표현식으로 변환하여 다른 실행을 위해 완전히 자동화 할 수 있습니다.

입력 행 수로 인해 육안 검사를 수행 할 수없는 경우에는 명령을 실행하기 전에 화면 (또는 더 나은 로그)에 명령을 에코하는 것이 좋습니다. 따라서 오류가 발생하면 어떤 명령이 발생했는지 정확하게 알고 있습니다 실패합니다. 그런 다음 원래 정규식으로 돌아가서 한 번 더 조정할 수 있습니다.


0

프로그램이 파이프를 무시하지만 파일을 인수로 허용하는 경우 특수 파일을 가리킬 수 있습니다 /dev/stdin.

Java에 익숙하지 않지만 다음은 bash에서 어떻게 수행하는지에 대한 예입니다.

$ echo $'pwd \n cd / \n pwd' |bash /dev/stdin
/home/rolf
/

bash가 \n개행 으로 변환하려면 $가 필요합니다 . 왜 그런지 잘 모르겠습니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.