하위 폴더의 특정 확장자를 가진 모든 파일에 대해 우아한 방식으로 작업을 수행하려면 어떻게합니까?


18

나의 현재 최선의 방법은 :

for i in $(find . -name *.jpg); do echo $i; done

문제 : 파일 이름에서 공백을 처리하지 않습니다.

참고 : "tree"명령과 같은 그래픽 방식을 사용하고 싶습니다.


단순히 따옴표를 넣을 수 없습니까 $i? 나는 그렇게하고 잘 작동합니다. 그 접근 방식에 문제가 있습니까?
Umar Farooq Khawaja

답변:


26

정식 방법은

find . -name '*.jpg' -exec echo {} \;

(교체 \;+더 이상의 파일을 통과 echo한 번에)

또는 (GNU에 따라 다르지만 일부 BSD에도 적용됩니다) :

find . -name '*.jpg' -print0 | xargs -r0 echo

zsh :

for i (**/*.jpg(D)) echo $i

2
xargs -0을 사용하는 경우 find -0
itsbruce

1
@ MichaelKjörling, 인용 부호 {}는 차이가 없습니다. {}은 쉘이 아니라 찾기로 확장됩니다. (최소한 유닉스 준수 echo와 같은) 이스케이프 시퀀스를 확장 하는 개선은 사용하지 않을 것 입니다. \becho
Stéphane Chazelas

1
@sch 확실합니까? find맨 쇼 find . -type f -exec file '{}' \;EXAMPLES섹션. 어쩌면 일부 껍질은 중괄호를 특별하게 취급 할 것입니다.
QuasarDonkey

1
따옴표는 해를 끼치 지 않지만 차이는 없습니다. 모든 '{}', \{\}, {}, "{}", '{'}"{"와 "}"그 두 자 찾기 위해 하나 개의 인수로 쉘 (어떤 본쉘 같은)에 의해 확장됩니다. "find"를 "echo find"로 바꾸거나 printf '<%s>\n' find다시 확인하십시오.
Stéphane Chazelas

@QuasarDonkey unix.stackexchange.com/questions/8647/… 참조
Gilles 'SO-stop

2

더 나은 답변이 이미 제공되었습니다.

그러나 코드에서 공백이 유일한 문제는 아닙니다. 탭, 줄 바꿈 및 와일드 카드 문자도 문제입니다.

IFS='
'
set -f
for i in $(find . -name '*.jpg'); do echo "$i"; done

그런 다음 줄 바꿈 문자 만 문제입니다.


1

당신이 언급 한 것은 사람들이 파일 이름을 읽으려고 할 때 직면하는 기본적인 문제 중 하나입니다. 때로는 지식이 부족하고 파일 및 폴더 구조에 대한 잘못된 개념을 가진 사람들은 " UNIX의 모든 것이 파일 입니다"라는 사실을 잊어 버리는 경향이 있습니다. 따라서 파일 이름은 공백이있는 둘 이상의 단어로 구성 될 수 있으므로 공백도 처리해야한다는 것을 이해하지 못합니다.

솔루션 : 이 작업을 수행하는 가장 잘 알려진 방법 중 하나는 깨끗한 읽기 를 수행하는 것 입니다.

우리는 여기에있는 모든 파일을 읽고 변수에 보관합니다. 다음에 원하는 처리를 할 때 파일 이름을 공백으로 유지하는 따옴표 안에 변수를 유지해야합니다. 이것은 기본적인 방법 중 하나이지만 다른 사람들이 제공 한 다른 답변도 잘 작동합니다.

스크립트 :

 find /path/to/files/ -iname "*jpg" | \
  while read I; do
   cp -v --parent "$I" /backup/dir/
  done

여기에 나는 그들에게 경로를 제공하여 파일을 읽고 있으며 내가 읽고있는 모든 것을 변수 I 안에 보관하고 있습니다. 나는 공간을 보존하여 올바르게 처리하기 위해 처리하는 동안 나중에 인용 할 것입니다.

이것이 어떤 식 으로든 도움이되기를 바랍니다.


1
"모든 것이 파일입니다"는 다른 것을 말합니다. 귀하의 솔루션은 GUN 전용이며 파일 이름의 백 슬래시 또는 줄 바꿈 문자에 대처하지 않습니다. 쉘 (IMO)의 "읽는 동안"루프는 종종 잘못된 쉘 스크립팅 실행을 나타냅니다.
Stéphane Chazelas

@sch : 허, 그리고 나는 생각했었다. 괜찮아. 지적 해 주셔서 감사합니다. 아마 좀 더 살펴 봐야 할 것 같습니다.
다크 나이트

죄송합니다, 나는 "GNU"가 아닌 "GUN"위 (내가 ... 사람들은 BTW 아나그램이다 처음으로 깨닫는 것)을 의미
스테판 Chazelas가

1

간단히과 findbash:

find . -name '*.jpg' -exec bash -c '
    echo "treating file $1 in bash, from path : ${1%/*}" 
' -- {} \;

이런 식으로, 우리 $1는 기본 스크립트처럼 bash에서 고급 작업을 수행하기위한 좋은 관점을 열어줍니다.

보다 효율적인 방법 (모든 파일에 대해 새 bash를 시작하지 않아도 됨) :

find . -name '*.jpg' -exec bash -c 'for i do
    echo "treating file $i in bash, from path : ${i%/*}" 
  done' -- {} +

0

최신 버전의 bash에서는 다음 globstar옵션을 사용할 수 있습니다 .

shopt -s globstar
for file in **/*.jpg ; do
    echo "$file"
done

간단한 동작을 위해 루프를 완전히 건너 뛸 수도 있습니다.

echo **/*.jpg

zsh (기능이 시작된 곳)와 ksh93 (으로 작동)에서 작동하지만 set -Gbash 버전은 grep -r디렉토리와의 심볼릭 링크 ( find -L하위 또는 zsh 와 동일)로 내려 가기 때문에 bash 버전이 기본적으로 손상되므로 (bash와 마찬가지로) bash에서 사용해서는 안됩니다 ***/*.jpg). 또한 찾기와는 달리, 도트 파일을 생략하고 dotdir로 내려 가지 않습니다 (기본적으로).
Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.