이름이 파일 목록의 줄과 일치하지 않는 디렉토리의 모든 파일을 삭제하십시오.


9

1000 개 이상의 파일이있는 디렉토리가 있습니다. 텍스트 파일에는 한 줄에 하나씩 약 50 개의 파일 이름이 있습니다. 파일 이름이 목록의 항목과 일치하지 않는 디렉토리의 모든 파일을 삭제하고 싶습니다. 가장 좋은 방법은 무엇입니까? 쉘 스크립트를 시작했지만 파일 이름을 확인하기위한 적절한 명령을 목록에서 확인할 수 없습니다. 감사.

답변:


8

파일을 삭제하는 방법에 대한 질문은 신중하게 처리해야한다는 것을 알고 있습니다. 내 첫 번째 대답은 너무 성급해서 파일 목록이 egrep과 함께 사용하기 위해 형식이 잘못되었다는 사실을 이해하지 못했습니다. 그 위험을 줄이기 위해 답을 편집했습니다.

이름에 공백이없는 파일에 대해서는 작동합니다.

먼저 정확한 파일 이름과 일치하도록 파일 목록을 다시 작성하십시오.

sed -e 's,^,^,' -e 's,$,$,'  filelist  > newfilelist 

rm 명령을 빌드하십시오

cd your_directory
ls | egrep -vf newfilelist   | xargs -n 1 echo rm  >  rmscript

rm 스크립트가 적합한 지 확인하십시오 ( "vim"또는 "less"로 수행 할 수 있음).
그런 다음 작업을 수행하십시오.

sh -x rmscript

파일 이름에 공백이 있으면 파일 이름에 공백이 있으면 "작동하지 않습니다.

ls | egrep -vf newfilelist  | sed 's,^\(.*\)$,rm "\1",' > rmscript

물론 파일 목록은 같은 디렉토리에 있어서는 안됩니다!

편집 :

Nathan의 파일 목록에는 디렉토리의 모든 파일과 일치하는 이름이 포함되어 있습니다 (예 : "html"은 "bob.html"과 일치). egrep -vf모든 스트림을 흡수 했기 때문에 삭제 된 것이 없습니다 . 각 파일 이름 주위에 "^"와 "$"를 넣는 명령을 추가했습니다. 나는 Nathan의 파일 목록이 정확하다는 것이 운이 좋았습니다. CR-LF로 끝나는 줄이나 추가 공백으로 DOS 형식이 되었습니까? egrep에 의해 파일이 보존되지 않았으며 모두 삭제되었습니다.


미리보기 명령을 실행하면 "rm"이있는 한 줄이 나타납니다. 실제 명령을 실행하면 rm에 대한 인수가 누락되었다는 오류 메시지가 나타납니다. ls의 결과를 사용하려면 특수 구문이 필요합니까 | xargs 입력에서 egrep?
Nathan

@Nathan 당신은 먼저 디렉토리로 CD를해야합니다. 특별한 구문이 없습니다. ls디렉토리 파일 이름을 제공하고 egrep -vf filelist50 파일 이름을 필터링하십시오. 모든 파일을 삭제 한 것 같습니다.
Emmanuel

@Emamanuel 삭제할 파일이 들어있는 디렉토리에서 명령을 실행하고 있습니다.
Nathan

@Nathan 모든 파일이 삭제 되었습니까?
Emmanuel

아뇨, 아직 거기 있어요
Nathan

1

다음에 대한 인수를 사전 구성하십시오 find.

{
  read -r
  keep=( -name "$REPLY" ) # no `-o` before the first one.
  while read -r; do
    keep+=( -o -name "$REPLY" )
  done
} < file_list.txt
find . -type f ! \( "${keep[@]}" \) -exec echo rm {} +

echo부품을 사용하여 구성 내용을 확인하십시오. echo실제로 실행할 부품을 제거하십시오 .

업데이트 : 데모 :

##
# Demonstrate what files exist for testing.
# Show their whitespace:
~/foo $ printf '"%s"\n' *
" op"
" qr"
"abc"
"def"
"gh "
"ij "
"k l"
"keep"
"m n"

##
# Show the contents of the "keep" file,
# Including its whitespace:
~/foo $ cat -e keep
keep$
abc$
gh $
k l$
 op$

##
# Execute the script:
~/foo $ { read -r; keep=( -name "$REPLY" ); while read -r ; do keep+=( -o -name "$REPLY" ); done } < keep
~/foo $ find . -type f ! \( "${keep[@]}" \) -exec rm {} +

##
# Show what files remain:
~/foo $ printf '"%s"\n' *
" op"
"abc"
"gh "
"k l"
"keep"


공간을 잘 처리하지는 못하지만 +1합니다. 아마도 작은 따옴표 ( ')를 추가해야 합니다 ( 예 : keep=( -name \'"$REPLY"\' )및) keep+=( -o -name \'"$REPLY"\' ).
Cristian Ciupitu

실수로 파일을 삭제할 수 있기 때문에 위의 내용은 위험합니다.
davidva

@CristianCiupitu 님이 아닌가요? 공백을 잘 다루는 데모를 추가했습니다.
kojiro

@davidva 어떤 상황에서? 당신이 물건을 삭제하는 것을 자동화 할 때마다 실수를 할 위험이 있지만 질문의 매개 변수 내에서 내 데모는이 접근법이 적절하다는 것을 증명합니다.
kojiro

1

zsh:

mylist=(${(f)"$(<filelist)"})
print -rl -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

filelist배열 의 행을 읽은 다음 glob 한정자 / e문자열 을 사용 하여 배열에없는 파일 이름 만 glob / 선택합니다. .일반 파일 만 선택하고 ( D목록에 dotfile이 포함 된 경우 추가 ) 부정 ^e_'expression'_된 항목은 어떤 식 반환 거짓, 즉 자신의 이름 (있는 경우 $REPLY) 배열의 요소가 아니다 .
당신이 결과에 만족하는 경우 교체 print -rlrm실제로 파일을 제거하려면 :

rm -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

재귀 적으로 파일을 선택하고 제거하려면 glob 수정 자 */**와 함께 ${REPLY:t}glob를 사용하십시오 .

rm -- */**(.^e_'(($mylist[(Ie)${REPLY:t}]))'_)

0

디렉토리의 내용을 파일에 넣으면 다음과 같습니다.

cd <somedirectory>
ls >> filelist

텍스트 편집기와 파일 목록 및 제외한 모든 파일을 제거 삭제할을 . 위의 답변에 반대되는 접근 방식이므로 대담합니다.

이 시도:

while read p || [[ -n $p ]]; 
echo $p
done < filelist

화면에 출력 된 파일 목록이 표시되면 다음과 rm -v같이 echo를로 바꾸십시오 .

while read p || [[ -n $p ]]; 
rm -v $p
done < filelist

0

아래 스크립트를 실행하십시오.

  1. 처음에는 디렉토리 안에있는 모든 파일을 찾고 출력을 다른 파일에 저장합니다 all_files.
  2. 우리는해야하는 파일의 목록이있는 파일이 없습니다 삭제를 ( not_to_be_deleted_files).
  3. 이 두 파일이 필요 하므로 파일 이름 not_to_be_deleted_filesfiles_to_be_deleted끝에 추가하고 not_to_be_deleted_files있습니다.
  4. 이제 linux join명령을 사용하여 삭제 해야하는 파일을 찾고 출력을 files_to_be_deleted 파일로 리디렉션 합니다.
  5. 이제 마지막 while 루프에서 모든 파일 이름을 읽고 해당 파일 이름에 files_to_be_deleted언급 된 파일을 제거합니다.

스크립트는 다음과 같습니다.

find /home/username/directory -type f | sed 's/.*\///' > all_files
echo all_files >> not_to_be_deleted_files
echo not_to_be_deleted_files >> not_to_be_deleted_files
echo files_to_be_deleted >> not_to_be_deleted_files
join -v 1 <(sort all_files_listed) <(sort files_not_to_be_deleted) >   files_to_be_deleted
while read file
rm  "$file"
done < files_to_be_deleted

추신 : 아마도 이것을 스크립트로 저장하고 실행하려면을 사용하여 스크립트 이름을 추가 할 수 있습니다 echo scriptname >> not_to_be_deleted_files.

꼭 필요한 것은 아니지만 나중에 후회하지 않기 때문에 선호합니다. 작은 파일 세트를 테스트했으며 시스템에서 작동했습니다. 그러나 확실하게하려면 test먼저 디렉토리 에서 시도한 다음 원래 디렉토리에서 파일을 제거하십시오.


0
  • 목록을 소스로 사용하여 목록의 모든 파일을 새롭고 비어있는 새 저장 디렉토리로 이동하십시오.
  • 목록의 파일 수와 저장된 파일 수를 비교하십시오.
  • 둘 다 일치하면 저장하지 않은 모든 파일을 원하는 방법으로 삭제하십시오.
  • 저장된 파일을 다시 이동하십시오.

0

나는 목록에 18.000 개의 파일이 있기 때문에 더 안전하고 훨씬 더 빠른 접근 방식을 찾았습니다! 대규모 Drupal 설치에서 이미지를 정리해야했습니다.

목록에없는 모든 파일을 삭제하는 것은 목록에있는 파일 만 유지하는 것과 같습니다. 그래서 실제로 파일을 목록에서 다른 위치로 복사하기로 결정했지만 20GB의 파일을 복사하면 공간이 너무 많이 걸리고 매우 느려집니다. 트릭은 옵션을 hardlinks사용하여 대신 파일을 복사 하는 -l것입니다 cp. 이것은 거의 공간을 차지하지 않으며 매우 빠릅니다. 또한 디렉토리 구조를 유지해야했기 때문에 --parents옵션을 사용했습니다 .

내 파일 목록에서 발췌 한 내용은 다음과 같습니다.

1px.png
misc/feed.png
modules/file/icons/x-office-presentation.png
modules/file/icons/x-office-spreadsheet.png
newsletter.png
sites/all/libraries/ckeditor/plugins/smiley/images/devil_smile.png
sites/all/libraries/ckeditor/plugins/smiley/images/regular_smile.png
sites/default/files/009313_PwC_banner_CBS_Observer_180x246px.jpg

예를 들어 temp는 대상입니다.

cp -l --parents 'misc/feed.png' temp

이것은이 구조를 만들 것입니다 :

temp
  misc
    feed.png

대상은 소스와 동일한 파일 시스템에 있어야 하드 링크가 작동합니다.

다음 단계는 스크립트를 구성하는 것입니다.

sed -e "s,^,cp -l --parents '," -e "s,$,' /some/where/temp," filelist > newfilelist

이제 빈 디렉토리 / some / where / temp를 이미 만들었다 고 가정하면 다음과 같이 파일을 복사 할 수 있습니다.

sh newfilelist 2> missing_files

에서 오류가 어떻게 발생하는지 확인하십시오 missing_files. 이 방법의 추가 보너스는 실제로 원래 목록에서 파일 목록을 얻는다는 것입니다 존재 하지 않는 !

스크립트를 실행 한 후 temp에는 파일 목록에있는 파일 만 포함되지만 아무것도 삭제하지 않고 추가 공간을 차지하지 않습니다. 결과에 만족하면 하위 폴더를 포함하여 모든 원본 파일을 삭제할 수 있습니다.

마지막으로 파일과 폴더를 임시 위치에서 원래 위치로 다시 이동하십시오.

18.000 파일의 경우 몇 초 밖에 걸리지 않았습니다.


0

안전하고 간단합니다.

cd 디렉토리에.

임시 디렉토리를 작성하십시오.

mv *.yourExlusionSelector.* ./temp
rm *
mv ./temp ./
rm -rf ./temp

끝난.


사이트에 오신 것을 환영합니다. OP가 언급 한 목록의 이름이 간단한 패턴 일치의 결과 인 경우 접근 방식이 효과가 있지만 (아주 잘 될 수 있습니다) OP는 제외 할 파일 이름이 특정 파일에 저장되어 있다고 언급했습니다. 하나의 정적 패턴에 의존하거나 잠재적으로 여러 패턴을 콘솔에 유형 복사하지 않고 해당 파일에서 제외 패턴을 읽도록 응답을 확장 할 수 있습니다.
AdminBee
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.