파일 이름에 따라 달라지는 플래그 인수를 사용하여 각 파일에 대해 명령을 실행합니다.

파일 이름에 따라 달라지는 플래그 인수를 사용하여 각 파일에 대해 명령을 실행합니다.

다음과 같은 이름의 파일이 포함된 폴더가 있다고 가정해 보겠습니다.

file1.txt
file2.txt
file2.txt

등. 다음과 같이 각각에 대해 명령을 실행하고 싶습니다.

mycommand file1.txt -o file1-processed.txt
mycommand file2.txt -o file2-processed.txt
mycommand file3.txt -o file3-processed.txt

등.

-processed이 사이트에는 몇 가지 유사한 질문이 있습니다. 차이점은 확장명 앞의 파일 이름 중간에 테스트를 삽입하고 싶다는 것입니다 .

find작업을 위한 도구가 될 것 같습니다 . 깃발 없이도 -o할 수 있어

find *.txt -exec mycommand "{}" ";"

그러나 {}구문은 등과 같이 전체 파일 이름을 제공하므로 파일 이름과 확장자 사이에 ""를 추가 file1.txt할 수 없습니다 . -processed간단한 bash 루프를 사용하면 for비슷한 문제가 있습니다 .

이 작업을 수행하는 쉬운 방법이 있습니까 find?

답변1

처리할 모든 파일이 동일한 폴더에 있는 경우에는 필요하지 않으며 find기본 셸 와일드카드를 사용할 수 있습니다.

for foo in *.txt ; do
  mycommand "${foo}" -o "${foo%.txt}-processed.txt"
done

쉘 관용구는 ${foo%bar}패턴(이 경우 확장자)과 일치하는 가장 작은 접미사 문자열을 값에서 제거하므로 원하는 접미사로 바꿀 수 있습니다.barfoo.txt

답변2

다양한 시스템에서 실행되는 스크립트를 작성하고 이식성을 염두에 두고 있다면 for반복하고 ${var%sfx}시작하는 것만 큼 좋은 것은 없습니다.사용자 1404316답변.

그러나 자신의 시스템에서 유사한 작업을 수행할 수 있는 편리한 방법을 찾고 있다면 진심으로 추천합니다.GNU 병렬, 이는 기본적으로 xargs스테로이드입니다. 특정 작업에 대한 솔루션은 다음과 같습니다.

parallel mycommand {} -o {.}-processed.txt ::: *.txt

그런 다음 문자열 목록 :::(셸이 *.txt일치하는 파일 이름 목록으로 확장됨)을 가져와 mycommand {} -o {.}-processed.txt각 문자열에 대해 실행하여 {}입력 문자열(예: xargs)과 {.}확장자가 없는 파일 이름을 바꿉니다.

stdin(를 통해 이 작업을 수행할 수 있습니다 .매개변수find-way), 또는 와 쌍을 이루지 만 확장된 글로브 외에는 locate거의 필요하지 않습니다 .zsh

보세요GNU 병렬 튜토리얼그것이 무엇을 할 수 있는지 알아보세요. 일괄 변환, 하위 디렉터리로 아카이브 추출 등을 위해 항상 사용합니다.

답변3

이것은 적응한다사용자 1404316의 답변작업 find:

find . -type f -name '*.txt' \
   -exec sh -c 'for file do mycommand "$file" -o "${file%.txt}-processed.txt"; done' sh {} +

(모든 내용을 한 줄에 입력할 수 있습니다. 은 생략하세요 \. 가독성을 높이기 위해 두 줄로 나누었습니다.)


가독성을 위해 형식을 지정하는 또 다른 방법으로 포함된 쉘 스크립트를 더 명확하게 만듭니다.

find . -type f -name '*.txt' -exec sh -c '
  for file
  do
    mycommand "$file" -o "${file%.txt}-processed.txt";
  done
' sh {} +

기본적으로 이름이 지정되지 않은 쉘 스크립트를 생성합니다.

for file
do
    mycommand "$file" -o "${file%.txt}-processed.txt"
done

(작은따옴표 사이의 문자열, 확장됨) 모든 파일 이름을 인수로 사용하여 '…'command()로 쉘에 전달합니다 . (일반적으로 인용이 필요하지 않으며 안에 중괄호를 사용하지도 않습니다 .)sh -c.txt{}"$file"

답변4

재귀 및 더 복잡한 문자열 교체가 필요한 경우 find, sed및 조합이 작동할 수 있습니다.xargs

find . -iname '*.txt' -printf "%p\0-o\0%p\0" | sed -z '3~3s/\.txt$/-processed&/' | xargs -0 -n 3 echo mycommand

예:

$ find
.
./bar baz.txt
./foo.txt
$ find . -iname '*.txt' -printf "%p\0-o\0%p\0" | sed -z '3~3s/\.txt$/-processed&/' | xargs -0 -n 3 echo mycommand
mycommand ./bar baz.txt -o ./bar baz-processed.txt
mycommand ./foo.txt -o ./foo-processed.txt

이 명령은 -printf "%p\0-o\0%p\0"파일 경로를 -oASCII NUL 문자로 구분하여 두 번 인쇄하고 세 번째 후행 줄마다 하나를 삽입합니다 sed. 그런 다음 한 번에 세 개의 인수(파일 이름 및 편집된 파일 이름)를 사용하여 명령을 실행합니다.-processed.txtxargs-o

관련 정보