알 수 없는 번호가 포함된 파일을 삭제하는 방법은 무엇입니까?

알 수 없는 번호가 포함된 파일을 삭제하는 방법은 무엇입니까?

다음과 같은 이름의 파일을 작성하는 코드가 있습니다.

body00123.txt
body00124.txt
body00125.txt

body-1-2126.txt
body-1-2127.txt
body-1-2128.txt

body-3-3129.txt
body-3-3130.txt
body-3-3131.txt

이렇게 하면 파일의 처음 두 숫자는 "음수"가 될 수 있지만 마지막 3개 숫자는 그렇지 않습니다.

다음과 같은 목록이 있습니다.

123
127
129

이 숫자 중 하나로 끝나지 않는 모든 파일을 삭제하고 싶습니다. 필요한 나머지 파일의 예는 다음과 같습니다.

body00123.txt

body-1-2127.txt

body-3-3129.txt

내 코드는 Python에서 실행되므로 다음을 시도했습니다.

for i not in myList:
     os.system('rm body*' + str(i) + '.txt')

이로 인해 모든 파일이 삭제됩니다.

답변1

때로는 "좋은" 파일을 다른 곳으로 옮기고 나쁜 파일을 삭제한 다음 좋은 파일을 다시 옮기는 것이 더 쉽습니다.

방법이 적합하다면 이것이 효과가 있을 수 있습니다.

#!/bin/sh

# Temporary directory to hold the files we want to keep
mkdir .keep || exit

for a in $(cat keeplist)
do
  # These are the files we want to keep
  mv body*$a.txt .keep

  # Except this might match negative versions, so remove them
  rm -f .keep/*-$a.txt
done

# Remove the files we don't want
rm body*

# Move the good files back
mv .keep/* .

# Tidy up
rmdir .keep

예를 들어 다음과 같이 시작한다면:

% ls
body-1-2126.txt  body-2-3-123.txt  body-3-3131.txt  body00125.txt  s
body-1-2127.txt  body-3-3129.txt   body00123.txt    fix
body-1-2128.txt  body-3-3130.txt   body00124.txt    keeplist

그런 다음 우리가 끝내는 스크립트를 실행

% ls
body-1-2127.txt  body-3-3129.txt  body00123.txt  fix  keeplist  s

답변2

존재하다 zsh:

$ set -o extendedglob
$ list=(123 127 129)
$ echo rm body(^*(${(~j[|])list})).txt
rm body00124.txt body00125.txt body-1-2126.txt body-1-2128.txt body-3-3130.txt body-3-3131.txt

( echo실제 수행된 작업 제거)

매개변수 j[|]확장 플래그는 j요소를 연결합니다. 이 플래그를 사용하면 전역 연산자(리터럴이 아닌 대체 연산자)로 해석됩니다.$list|~|

따라서 glob은 부정 연산자로서 body(^*(123|127|129)).txt로 끝나 므로 일치하는 파일 이름은 으로 시작하고 그 뒤에 123, 127, 129로 끝나지 않는 문자열이 오고 마지막으로 .^extendedglobbody.txt

추가 조건이 필요한 경우 다음 *으로 바꾸십시오. 이 숫자 앞의 부분을 유지하려면 이 숫자 앞의 부분은 이 숫자로 끝날 수 없으므로 example이라는 파일도 삭제됩니다.(^*-)-body-1-1-123.txt

더 엄격한 일치를 위해 다음을 수행할 수도 있습니다.

n='((-|)[0-9])' # digit with an optional - sign
echo rm body$~n(#c2)($~n(#c3)~(${(~j[|])list})).txt

여기서 (#c2)는 반복 연산자이고 는 ~예외(및 아님) 연산자입니다. 내용이 리터럴 문자열이 아닌 패턴으로 해석된다는 점을 제외하면 $~n유사합니다 ( 위의 매개변수 확장 플래그에서처럼).$n$n~

따라서 우리는 body뒤에 두 개의 숫자가 오는 것을 일치시킵니다. 각 숫자는 -선택적으로 앞에 하나와 뒤에 세 개의 숫자가 옵니다. 단, 의 구성원 중 하나인 숫자는 제외하고 그 $list뒤에 숫자가 옵니다 .txt.

답변3

find이름과 일치하지 않거나 이름 목록과 일치하지 않는 파일에 대한 작업을 허용하기 위해 무효화할 수 있는 이름 일치 기본 요소가 있습니다.

find기본값은 여러 작업을 한 줄에 그룹화하는 것이므로 다음 과 같은 스크립트 and를 작성할 수 있습니다 bash.

#!/usr/bin/env bash

list=( 123 127 129 )

findcmd="find . -type f $(printf -- ' -not -name \*%s.txt' "${list[@]}")"

bash -v <<< "$findcmd"

(참고: 이 bash줄은 다음과 같이 수행할 수도 있습니다.

printf '%s\n' "$findcmd"
eval $findcmd

)

이 스크립트의 출력은 다음과 같습니다.

find . -type f  -not -name \*123.txt -not -name \*127.txt -not -name \*129.txt
./body-3-3130.txt
./body00125.txt
./body-1-2126.txt
./body00124.txt
./body-1-2128.txt
./body-3-3131.txt

여기에는 두 가지 정보가 있습니다. find보관할 숫자 배열로 작성된 명령 구문과 해당 숫자와 일치하지 않는 결과 파일 목록입니다.

파일 이름 목록을 다시 확인하세요. 이러한 파일을 모두 삭제할 것인지 확인한 후 find명령 구문을 복사하여 아래와 같이 find작업 지침 과 함께 붙여넣습니다(가독성을 위해 백슬래시로 이스케이프된 줄바꿈을 사용하여 표시합니다).-exec rm -v {} \;

$ find . -type f  -not -name \*123.txt -not -name \*127.txt -not -name \*129.txt \
    -exec rm -v {} \;
./body-3-3130.txt
./body00125.txt
./body-1-2126.txt
./body00124.txt
./body-1-2128.txt
./body-3-3131.txt

답변4

파이썬. 직접적인 방법

import os
import glob

num_lst = [123, 127, 129]
num_as_str_set = set(map(str, num_lst))

# If not other files except .txt in directory, listdir() will be enough
#for filename in os.listdir():
for filename in glob.glob("*.txt"):
    #7654321
    #123.txt
    #[-7:-4] -> 123
    if filename[-7:-4] not in num_as_str_set:
        print("remove", filename)
# Uncomment to remove files
#       os.remove(filename)

Bash에서도 동일한 논리

declare -A hash_map
hash_map=( [123]= [127]= [129]= )

for fn in *.txt; do
    key="${fn: -7:-4}"
    if ! [[ -v hash_map["$key"] ]]; then
        echo "$fn"
#Uncomment to actual remove
#       rm -v "$fn"
    fi  
done

파이썬. 까다롭지만 아마도 최선의 방법은 아닐 것입니다.(벤치마크 필요)

import os
from glob import glob
from itertools import chain

num_lst = [123, 127, 129]
s = set(glob("*.txt")) - set(chain(*(glob(f"*{num}.txt") for num in num_lst)))
#Uncomment to remove files
#list(map(os.remove, s))

관련 정보