파일을 제거하지만 목록의 모든 파일을 제외


17

정기적으로 폴더를 정리해야합니다. 텍스트가 포함 된 파일 목록과 허용되는 파일을 얻습니다. 이제이 파일에없는 모든 파일을 삭제해야합니다.

예:

dont-delete.txt:

dontdeletethisfile.txt
reallyimportantfile.txt
neverdeletethis.txt
important.txt

내 폴더 정리에는 다음이 포함되어 있습니다.

ls /home/me/myfolder2tocleanup/:

dontdeletethisfile.txt
reallyimportantfile.txt
neverdeletethis.txt
important.txt
this-can-be-deleted.txt
also-waste.txt
never-used-it.txt

따라서이 파일을 삭제해야합니다.

this-can-be-deleted.txt
also-waste.txt
never-used-it.txt

파일에서 제공하는 일부 파일을 제외하는 옵션으로 삭제 명령을 작성하기 위해 무언가를 검색합니다.


이것은 숙제입니까?
— mook765

당신이 그의 선생님이 아니길 바랍니다. lol
— 구자라트 산타나

2
@gujarat 우리는 무료 숙제 서비스가 아니므로 의견이 정당합니다. 질문 자체는 다른 사람들에게 유용 할 수 있으므로 지금까지 열려 있습니다.
— Sergiy Kolodyazhnyy

@Serg 전적으로 당신에게 동의합니다
— Gujarat Santana

답변:


9

rm명령을 확인하고는 필요에 작동하고 있음을 확인할 수 있도록 주석. 그런 다음 해당 줄의 주석을 해제하십시오.

이 check directory섹션에서는 실수로 잘못된 디렉토리에서 스크립트를 실행하고 잘못된 파일을 클로버하지 않도록합니다.

echo deleting줄을 제거하여 자동으로 실행할 수 있습니다 .

#!/bin/bash

cd /home/me/myfolder2tocleanup/

# Exit if the directory isn't found.
if (($?>0)); then
    echo "Can't find work dir... exiting"
    exit
fi

for i in *; do
    if ! grep -qxFe "$i" filelist.txt; then
        echo "Deleting: $i"
        # the next line is commented out.  Test it.  Then uncomment to removed the files
        # rm "$i"
    fi
done

쓸모없는 사용ls 과 출력의 쓸모없는 캡처 를 피하기 위해 코드가 편집 grep되어 일치하는 것이 있는지 여부가 있습니다. 또한 이스케이프 문제를 피하기 위해 고정 문자열 패턴을 사용했습니다.
— David Foerster

@DavidFoerster 기부 해 주셔서 감사합니다. 그러나 while루프를 for루프로 변경하면 실수로 iteration key에서 i를 (으) 로 변경 했습니다 f. 선언에서 코드를 위반했습니다. 나는 그것을 고쳤다.
— LD James

죄송합니다. 습관의 힘. 파일 이름에 대한 쉘 변수 이름을로 사용하는 경향이 f있습니다. ;-P (… 그리고 내가 이전에 잊어 버린 대답에 +1)
— David Foerster

10

이 파이썬 스크립트는 이것을 할 수 있습니다 :

#!/usr/bin/env python3
import os
no_remove = set()
with open('./dont-delete.txt') as f:
     for line in f:
         no_remove.add(line.strip())

for f in os.listdir('.'):
    if f not in no_remove:
        print('unlink:' + f ) 
        #os.unlink(f)

중요한 부분은 os.unlink()기능 을 주석 해제하는 것입니다.

참고 :이 스크립트와 스크립트를 추가 dont-delete.txt하여 dont-delete.txt둘 다 목록에 있고 동일한 디렉토리에 보관하십시오.


1
set두 번째 부분에서 O (n) 조회 대신 O (1) 대신 목록 을 사용하도록 코드를 변경했습니다 .
— David Foerster

귀하의 도움에 감사드립니다, 나는 일반적으로 Windows 사람이지만, 파이썬 이음새도 시원합니다 =)
— stefan83

1
@ stefan83 : 파이썬은 Windows에서도 잘 실행됩니다.
— David Foerster

3

하나의 라이너가 있습니다.

comm -2 -3 <(ls) <(sort dont_delete) | tail +2 | xargs -p rm
  1. ls 현재 디렉토리의 모든 파일을 정렬 된 순서대로 인쇄합니다
  2. sort dont_delete 삭제하지 않으려는 모든 파일을 정렬 된 순서로 인쇄합니다
  3. <()연산자는 파일 - 류의 객체로 문자열을 변
  4. 이 comm명령은 두 개의 미리 정렬 된 파일을 비교하여 서로 다른 행을 인쇄합니다.
  5. -2 -3플래그를 사용하면 comm첫 번째 파일에 포함 된 행만 인쇄하고 두 번째 파일에는 인쇄하지 않고 삭제하는 것이 안전한 파일 목록이됩니다.
  6. tail +2호출은 단지의 제목 제거하는 것입니다 comm입력 파일의 이름이 포함 된 출력을,
  7. 이제 표준 출력에서 ​​삭제할 파일 목록을 얻습니다. 이 출력을 파이프 xargs하여 출력 스트림을의 인수 목록으로 바꿉니다 rm. 이 -p옵션은 xargs실행 전에 확인을 요구합니다.

당신의 도움을 위해 thx, 지금 나는 나의 해결책이있다!
— stefan83

@gardenhead, 코드가 피곤했지만 디렉토리의 모든 파일을 제거하고 dont-delete 목록의 첫 번째 파일과 마지막 파일 만 유지합니다. 이 문제에 대한 아이디어가 있습니까? 미리 감사드립니다.
— Negar

1

그래도 glob 한정자를 zsh사용하여에서 기본적 으로이 작업을 수행 할 수있는 것처럼 보입니다 (+cmd).

설명하기 위해 일부 파일부터 시작하겠습니다

 % ls
bar  baz  bazfoo  keepfiles.txt  foo  kazoo

화이트리스트 파일

 % cat keepfiles.txt
foo
kazoo
bar

먼저 화이트리스트를 배열로 읽습니다.

 % keepfiles=( "${(f)$(< keepfiles.txt)}" )

또는 아마도 더 나은

 % zmodload zsh/mapfile
 % keepfiles=( ${(f)mapfile[./keepfiles.txt]} )

(bash의 mapfile내장 또는 동의어와 동일 readarray). 이제 ${keepfiles[(I)filename]}일치하는 것이 없으면 0을 반환 하는 키를 사용하여 배열에 키 (파일 이름)가 있는지 확인할 수 있습니다 .

 % print ${keepfiles[(I)foo]}
1
 % print ${keepfiles[(I)baz]}
0
 %

이것을 사용 하여 배열에 true일치하는 것이 없으면 반환하는 함수를 만들 수 있습니다 $REPLY.

% nokeep() { (( ${keepfiles[(I)$REPLY]} == 0 )); }

마지막으로이 함수를 명령에서 한정자로 사용합니다.

 % ls *(+nokeep)
baz  bazfoo  keepfiles.txt

또는 귀하의 경우

 % rm -- *(+nokeep)

화이트리스트 파일 자체의 이름을 화이트리스트에 추가하고 싶을 것입니다.


0

bash 쉘이 extglob shopt설정되어 있다고 가정하면 다소 보수적 인 대안이 있습니다.

rm !($(tr \\n \| < keep.txt))

(... @gardenhead의 다른 우수한 통신 제안과 함께!)


0

Ubuntu 의 출력 ls /home/me/myfolder2tocleanup/이 최대 쉘 인수 제한 ARG_MAX 을 약 2MB 를 초과 하지 않는 한 다음을 제안합니다.


작업을 수행하는 한 줄 명령 구현은 다음과 같습니다.

  1. 다음 dont-delete.txt과 같이 삭제할 파일이 포함 된 디렉토리에 파일을 복사하십시오 .
cp dont-delete.txt /home/me/myfolder2tocleanup/
  1. cd 다음과 같이 삭제 될 파일이 들어있는 디렉토리로
cd /home/me/myfolder2tocleanup/
  1. 드라 이런을 수행하여 명령을 테스트하고 실제로 삭제하지 않고 삭제 된 것으로 탐지 된 파일의 이름을 인쇄하십시오.
ls -p | grep -v / | sed 's/\<dont-delete.txt\>//g' | sort | comm -3 - <(sort dont-delete.txt) | xargs echo | tr " " "\n"
  1. 출력에 만족하면 다음과 같이 명령을 실행하여 파일을 삭제하십시오.
ls -p | grep -v / | sed 's/\<dont-delete.txt\>//g' | sort | comm -3 - <(sort dont-delete.txt) | xargs rm

설명 :

  • ls -p현재 디렉토리의 모든 파일과 디렉토리 를 나열 하고 옵션 -p은 /디렉토리 이름에 a 를 추가 합니다.
  • grep -v //이름에 a 를 포함하는 모든 항목을 제거하여 디렉토리를 제외 합니다.
  • sed 's/\<dont-delete.txt\>//g'dont-delete.txt파일 을 제외 하므로 프로세스에서 삭제되지 않습니다.
  • sort의 나머지 출력을 정렬합니다 ls.
  • comm -3 - <(sort dont-delete.txt)dont-delete.txt파일 을 정렬하고 정렬 된 출력과 비교 ls하여 둘 다에 존재하는 파일 이름을 제외시킵니다.
  • xargs rm이미 처리 된의 출력에서 ​​나머지 파일 이름을 모두 제거합니다 ls. 현재의 모든 디렉토리에있는 항목을 제외하고 제거됩니다이 수단 디렉토리 , 에 나열된 파일 dont-delete.txt파일 및 파일 자체dont-delete.txt

드라 이런 부분에서 :

  • xargs echo 제거해야 할 파일을 인쇄합니다.
  • tr " " "\n" 가독성을 높이기 위해 공백을 새 줄로 변환합니다.

0

rsync여기에 게시 된 솔루션 을 사용하는 것이 좋습니다 . 그렇지 않으면 언급 된 예외적 인 조건으로 아래 솔루션을 사용하십시오.

파일에 공백 파일 (공백 / 탭)이 없다고 가정하면 excludelist다음과 같이 할 수 있습니다.

find /path/to -type f \( ! -name "excludelist" $(printf ' -a ! -name %s\n' $(< excludelist)) \)

excludelist 파일에 -delete존재하지 않는 파일을 삭제하려면 위 명령에 추가 하십시오. 찾기에 옵션 이 없으면 다음 과 같이 사용할 수 있습니다 .-deleterm-exec

find /path/to -type f \( ! -name "excludelist" $(printf ' -a ! -name %s\n' $(< excludelist)) \) -exec echo rm {} \;

또는 사용 -exec과 +터미네이터 대신.

find /path/to -type f \( ! -name "excludelist" $(printf ' -a ! -name %s\n' $(< excludelist)) \) -exec echo rm {} +

echo 드라 이런에 사용됩니다.


-1

내 제안은 :

sed -e 's/^/\.\//' dont-delete.txt > dont-delete-relative-path.txt
find . -type f -print | grep -Fxvf dont-delete-relative-path.txt | xargs -d'\n' rm

2018-08-07 업데이트

예:

1: mkdir /tmp/delete-example && cd /tmp/delete-example
2: touch a b c d
3: echo "./a\n./b\n./dont-delete.txt\n" > dont-delete.txt
4: find . -type f -print | grep -Fxvf dont-delete.txt | xargs -d'\n' rm

3 행 뒤에는 dont-delete.txt내용 이 포함 된 파일이 있습니다.

./a
./b
./dont-delete.txt

(리딩 ./은 매우 중요합니다 )

파일 c및이 d삭제됩니다.


줄 바꿈으로 구분 된 파일 이름의 텍스트 파일로 이것을 시도했습니다. 디렉토리의 모든 파일이 삭제되었습니다.
— 자크 말라 프레이드

당신의 "유지 목록"이 틀렸다고 생각합니다.
— NYXZ

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