이름에 \ n 문자가있는 폴더의 for 루프


9

\n이름 이있는 폴더가 있습니다.

예를 들면 다음과 같습니다.

$ ls
''$'\n''Test'

테스트 이름이있는 폴더와 이름 앞에 빈 줄이 있습니다.

따라서 부모 디렉토리에서 이와 같은 스크립트를 실행할 때 :

while IFS= read -r d; do 
    rmdir $d
done < <(find * -type d)

이것은 보여준다:

rmdir: failed to remove '': No such file or directory
rmdir: failed to remove 'Test': No such file or directory

폴더 이름에는 두 줄이 있기 때문에 한 번에 두 번 실행 \n되고 다른 한 번에 실행 Test되기 때문입니다.

따라서이 문제를 어떻게 해결할 수 \nTest있습니까? 스크립트는 하나의 폴더 일뿐입니다.


3
find의 -print0지시문과 -dread 옵션 을 사용해야 합니다.
glenn jackman

1
@glennjackman 대답하십시오!
디저트

@glennjackman 답장을 보내 주셔서 감사하지만 find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; done명령에이 출력이 표시 rmdir: failed to remove 'Test': No such file or directory됩니다.
Tara S Volpe 2016 년

5
당신은 해야한다 변수를 인용 :rmdir "$file"
글렌 잭맨

1
@glennjackman 답변으로 게시하십시오. 적절한 해결책이며 주석 외에는 그다지 적합하지 않습니다.
공감은

답변:


12

거기에는 명령이 하나뿐이므로 플래그 호출 로 호출 find하면 충분합니다 .-execrmdir

find -depth -type d -exec rmdir {} \;

또는 -delete에서 find -type d -delete와 같이 옵션을 사용 하지만 비어 있지 않은 디렉토리에서는 작동하지 않습니다. 이를 위해 -empty깃발 도 필요합니다 . 또한 건너 뛸 수 -delete있음을 의미합니다 -depth. 따라서 모든 것을 하나의 프로세스로 유지하는 또 다른 실행 가능한 대안 :

find -type d -empty -delete

디렉토리가 비어 있지 않으면를 사용하십시오 rm -rf {} \;. \n파일 이름으로 디렉토리 만 분리하기 위해 bash의 ANSI-C 따옴표 $'...'-nameopption 과 결합 할 수 있습니다 .

find  -type d -name $'*\n*' -empty -delete

POSIX-ly, 우리는 다음과 같이 처리 할 수 ​​있습니다.

find -depth  -type d -name "$(printf '*\n*' )" -exec rmdir {} \;

디렉토리를 제거하는 것이 목표라면 -delete충분하지만 디렉토리에서 명령을 실행하려면 -exec가장 적합 하다는 점을 언급 할 가치가 있습니다 .

또한보십시오


2
rm -rf 주의해서 사용 하십시오 . ; P는하지 않습니다 find-deleteBTW 옵션을? 빈 디렉토리를 삭제하고 비어 있지 않은 디렉토리에 대한 오류를 발생시킵니다 rmdir.
디저트

3
@dessert 그렇게하고 추가했지만 -delete비어 있지 않은 디렉토리는 제거하지 않습니다. 따라서, 신중한 사용rm -rf
Sergiy Kolodyazhnyy

6
항상 드라이가 운영하는 find(즉,이 제거 어떤 파괴적인 페이로드없이 명령 -delete또는 -exec whatever \;영향을받는 파일의 목록이 ... 실제로 정확하고 삭제되지해야 물건을 포함하지 않는 경우 확인)
바이트 사령관

2
이것은 askubuntu.com이므로 GNU를 가정 할 수 있습니다 find. -exec rmdir {} +하나의 rmdir명령 줄 에 여러 인수를 배치하는 데 사용 합니다 . 그리고 BTW " 하지만 비어 있지 않은 디렉토리에서는 작동하지 않습니다. "도 적용 rmdir되므로 실제로는와 다릅니다 -delete. 의 차이점입니다 rm -r.
Peter Cordes 2016 년

2
find -type d -empty -delete()를 -delete의미 -depth합니다.
Kevin

10

쉘 글로브를 사용할 수 있습니다 find:

for d in */ ; do 
    rmdir "$d"
done

쉘 glob */는 현재 디렉토리의 모든 폴더와 일치합니다. 이 for-loop 구성은 정확한 단어 분리를 자동으로 처리합니다.

쉘 옵션에 따라 숨겨진 폴더 (이름은.로 시작)를 무시할 수 있습니다. 이 동작은 명령을 사용하여 현재 세션의 모든 파일과 일치하도록 변경할 수 있습니다 shopt -s dotglob.

또한 항상 변수를 인용하는 것을 잊지 마십시오.


글로브는뿐만 아니라 재귀처럼, 현재 디렉토리에있는 파일 / 디렉터리를 찾을 find않습니다
ilkkachu

1
당신은 맞습니다 @ilkkachu. globstar shell 옵션을 활성화하고 대신 glob를 shopt -s globstar사용하여 변경할 수 있습니다 **/*/.
바이트 사령관

6

지금까지 작성된 두 답변 rmdir은 디렉토리 당 한 번만 호출 하지만 rmdir여러 가지 인수를 취할 수 있으므로 더 효율적인 방법이 없습니까?

하나는 간단하게 할 수 있습니다

rmdir */

이것이 가장 쉽고 효율적인 방법이지만 많은 디렉토리 의 경우 오류가 발생할 수 있습니다 ( gnome-terminal에서 명령 행 인수의 최대 길이는 얼마입니까? 참조 ). 이 접근 방식이 재귀 적으로 작동하도록하려면 globstar쉘 옵션을 활성화하고 대신 shopt -s globstar사용하십시오 .**/*/*/

GNU를 사용하면 find(그리고 사용하고 싶지 않다면 -delete) 할 수 있습니다

find -depth -type d -exec rmdir {} +

"명령 줄을 xargs작성 하는 것과 거의 같은 방식으로 "명령 줄 을 작성합니다 ( man find). 대체 -depth에 대한 -maxdepth 1당신이 반복적으로 일을하지 않으려면.

세 번째이자 IMO의 화려한 방법은 이 답변 에서 steeldriver에 의해 설명됩니다 .

printf '%s\0' */ | xargs -0 rmdir

이것은 셸 내장 printf을 사용하여 0으로 구분 된 인수 목록을 작성한 다음이 목록을 파이프하여 필요한만큼 정확하게 xargs호출 rmdir합니다. 위와 같이 shopt -s globstar또는 **/*/대신에 재귀 적으로 작동하게 할 수 있습니다 */.


2
find재귀 적이지만 OP의 루프는 그렇지 않습니다. 해당 동작을 복제하려면을 사용하십시오 find -maxdepth 1 -type d -exec rmdir {} +. ( -depth이 경우에는 중복됩니다.) printf에뮬레이션 과 깔끔한 ​​트릭 find -print0은 전에는 보지 못했습니다.
Peter Cordes 2016 년

1
오! 나는보고 lswhile루프, 나는 그들이 함께 프로세스 치환에서 리디렉션 된 놓친 find대신 파이프 ls루프에 그냥 몇 가지 이유로 그것을 보여주는 없습니다. 그것은 find *실제로 묻혀있다. 예, 재귀 적이며 디렉토리를 사용하지 않기 때문에 디렉토리를 포함하여 디렉토리에 디렉토리 항목이 너무 많으면 실패합니다 */. bash의 glob 확장보다 ing 에서 더 빠르기 find .때문에 훨씬 낫습니다 . findstat
Peter Cordes 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.