stdin / stdout 리디렉션이있는 xargs


21

나는 달리고 싶다 :

./a.out < x.dat > x.ans

각 *에 대한 .DAT 디렉토리에있는 파일 .

물론 bash / python / whateverever 스크립트로 수행 할 수는 있지만 섹시한 원 라이너를 작성하는 것을 좋아합니다. 내가 도달 할 수있는 것은 (여전히 stdout없이)입니다.

ls A/*.dat | xargs -I file -a file ./a.out

그러나 xargs의 -a 는 replace-str 'file'을 이해하지 못합니다.

도움을 주셔서 감사합니다.


여기에있는 다른 좋은 대답 외에도 GNU xargs의 -a 옵션을 사용할 수 있습니다.
James Youngman

답변:


30

우선, 출력을 파일 목록으로 사용하지 마십시오ls . 쉘 확장 또는을 사용하십시오 find. ls + xargs 오용 의 잠재적 결과 와 올바른 xargs사용법 의 예는 아래를 참조하십시오 .

1. 간단한 방법 : for 루프

아래의 파일 만 처리하려면 A/간단한 for루프로 충분합니다.

for file in A/*.dat; do ./a.out < "$file" > "${file%.dat}.ans"; done

2. pre1 왜 안돼   ls | xargs ?

다음 은 업무에 ls함께 사용하면 상황이 어떻게 변할 수 있는지에 대한 예입니다 xargs. 다음 시나리오를 고려하십시오.

  • 먼저 빈 파일을 만들어 봅시다 :

    $ touch A/mypreciousfile.dat\ with\ junk\ at\ the\ end.dat
    $ touch A/mypreciousfile.dat
    $ touch A/mypreciousfile.dat.ans
    
  • 파일을 참조하십시오.

    $ ls -1 A/
    mypreciousfile.dat
    mypreciousfile.dat with junk at the end.dat
    mypreciousfile.dat.ans
    
    $ cat A/*
    
  • 다음을 사용하여 마술 명령을 실행하십시오 xargs.

    $ ls A/*.dat | xargs -I file sh -c "echo TRICKED > file.ans"
    
  • 결과:

    $ cat A/mypreciousfile.dat
    TRICKED with junk at the end.dat.ans
    
    $ cat A/mypreciousfile.dat.ans
    TRICKED
    

당신은 단지 관리했습니다 그래서 모두 덮어 mypreciousfile.datmypreciousfile.dat.ans. 해당 파일에 내용이 있으면 지워졌을 것입니다.


2. 사용   xargs : 적절한 방법으로  find 

사용을 주장 xargs하려면 -0(널 종료 이름)을 사용하십시오.

find A/ -name "*.dat" -type f -print0 | xargs -0 -I file sh -c './a.out < "file" > "file.ans"'

두 가지 사항에 유의하십시오.

  1. 이 방법으로 당신은 .dat.ans결말로 파일을 만들 것입니다 ;
  2. 끊어집니다 일부 파일 이름에 인용 부호를 포함하는 경우 ( ").

두 가지 문제는 서로 다른 쉘 호출 방식으로 해결할 수 있습니다.

find A/ -name "*.dat" -type f -print0 | xargs -0 -L 1 bash -c './a.out < "$0" > "${0%dat}ans"'

3. 모든 내에서 수행 find ... -exec

 find A/ -name "*.dat" -type f -exec sh -c './a.out < "{}" > "{}.ans"' \;

이것은 다시 .dat.ans파일을 생성 하고 파일 이름에을 포함하면 중단됩니다 ". 그것에 대해하려면 bash호출 방식을 사용 하고 변경하십시오.

 find A/ -name "*.dat" -type f -exec bash -c './a.out < "$0" > "${0%dat}ans"' {} \;

ls의 출력을 구문 분석하지 않는다고 언급하면 ​​+1입니다.
rahmu

2
파일 이름에 ".이 포함 된 경우 옵션 2가 중단됩니다.
thiton

2
아주 좋은 지적입니다, 감사합니다! 그에 따라 업데이트하겠습니다.
rozcietrzewiacz

난 그냥 경우 있음을 언급 원하는 zsh하지 고려해야 할 필요 (파일 이름 등의 "공백), 쉘로 사용된다 (그리고 SH_WORD_SPLIT이 설정되지 않은) 모든 불쾌한 특별한 경우를 사소한. for file in A/*.dat; do ./a.out < $file > ${file%.dat}.ans ; done작품을 모든 경우에.
jofel을

-1 stdin으로 xargs를 수행하는 방법을 알아 내려고 노력 중이고 내 질문은 파일 또는와 관련이 없습니다 find.
Mehrdad

2

다음과 같이 해보십시오 (사용하는 쉘에 따라 구문이 약간 다를 수 있음).

$ for i in $(find A/ -name \*.dat); do ./a.out < ${i} > ${i%.dat}.ans; done


작동하지 않습니다. 그것은 같은 작업을 수행 somefile.dat.dat하고 모든 출력을 단일 파일로 리디렉션 하려고 시도 합니다.
rozcietrzewiacz

네가 옳아. 해결하기 위해 솔루션을 편집했습니다.
rahmu

OK-거의 양호 :) 그냥 somefile.dat.ans출력물이 그렇게 좋지 않을 것입니다.
rozcietrzewiacz

1
편집했습니다! 나는 '%'에 대해 몰랐다. 팁 덕분에 매력처럼 작동합니다.
rahmu

1
을 추가하면 -type file좋을 수 없으며 ( < directory), 특이한 파일 이름 요정이 슬프게됩니다.
Mat

2

간단한 패턴의 경우 for 루프가 적합합니다.

for file in A/*.dat; do
    ./a.out < "${file}" > "${file%.dat}.ans" # Never forget the QUOTES!
done

파일을 나열하기 위해 다른 유틸리티가 필요한 더 복잡한 경우 (zsh 또는 bash 4는 거의 필요하지 않은 강력한 패턴을 가지고 있지만 POSIX 쉘 내에 머물거나 대시와 같은 빠른 쉘을 사용하려면 무엇이든 찾아야합니다. 읽기가 가장 적절하지만)

find A -name '*.dat' -print | while IFS= read -r file; do
   ./a.out < "${file}" > "${file%.dat}.ans" # Never forget the QUOTES!
done

읽기는 기본적으로 줄 지향적이므로 공백을 처리합니다. 줄 바꿈을 처리하지 않으며 백 슬래시를 처리하지 않습니다. 기본적으로 이스케이프 시퀀스를 해석하므로 실제로 줄 바꿈을 전달할 수 있지만 find는 해당 형식을 생성 할 수 없습니다. 많은 셸은 -0모든 문자를 처리 할 수 있는 옵션을 제공하지만 불행히도 POSIX가 아닙니다.



1

나는 xargs에서 적어도 쉘 호출이 필요하다고 생각합니다.

ls A/*.dat | xargs -I file sh -c "./a.out < file > file.ans"

편집 : 파일 이름에 공백이 있으면이 방법이 작동하지 않습니다. 작동하지 않습니다. find -0 및 xargs -0을 사용하여 xargs가 공백을 올바르게 이해하도록하더라도 -c 쉘 호출은 해당 공간을 손상시킵니다. 그러나 OP는 명시 적으로 xargs 솔루션을 요청했으며 이것이 내가 생각해 낸 최고의 xargs 솔루션입니다. 파일 이름의 공백이 문제인 경우 find -exec 또는 쉘 루프를 사용하십시오.



@rozcietrzewiacz : 일반적으로,하지만 xargs 부두를하려고하는 사람이 이것을 알고 있다고 가정합니다. 이러한 파일 이름은 다른 셸 확장을 거치므로 어쨌든 잘 동작해야합니다.
thiton

1
쉘 확장이 잘못되었습니다. ls탈출 및 공백없이 같은 것을 출력 이는 문제이다.
rozcietrzewiacz

@ rozcietrzewiacz : 예, 그 문제를 이해합니다. 이제이 공백들을 제대로 빠져 나와 xargs로 가져 오겠다고 가정 해 봅시다 : 그것들은 sh의 -c 문자열로 교체되고, -c 문자열을 토큰 화하고 모든 것이 깨집니다.
thiton

예. 파싱 ls은 좋지 않습니다. 그러나 찾기와 함께 안전하게 사용할 xargs 있습니다-내 대답에서 제안 No 2를 참조하십시오.
rozcietrzewiacz

1

복잡 할 필요는 없습니다. for루프로 할 수 있습니다 .

for file in A/*.dat; do
  ./a.out < "$file" >"${file%.dat}.ans"
done

${file%.dat}.ans비트는 제거 .dat에서 파일 이름에서 파일 이름 접미사를 $file대신 추가 .ans끝.

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