filename.12345.end 형식의 파일이 수천 개 있습니다. 나는 모든 12 번째 파일 만 유지하기를 원하므로 file.00012.end, file.00024.end … file.99996.end 및 다른 모든 것을 삭제하십시오.
파일 이름 앞에 파일 번호가 더있을 수도 있으며 일반적으로 다음과 같은 형식입니다. file.00064.name.99999.end
Bash 셸을 사용하여 파일을 반복하는 방법을 파악한 다음 번호를 알아 내고 number%%12=0
파일 이 삭제 되는지 여부를 확인할 수 없습니다. 누구든지 나를 도울 수 있습니까?
감사합니다, 도리 나
답변
다음은 Perl 솔루션입니다. 이것은 수천 개의 파일에 대해 훨씬 빠릅니다.
perl -e '@bad=grep{/(\d+)\.end/ && $1 % 12 != 0}@ARGV; unlink @bad' *
다음과 같이 더 요약 될 수 있습니다.
perl -e 'unlink grep{/(\d+)\.end/ && $1 % 12 != 0}@ARGV;' *
파일이 너무 많고 simple을 사용할 수없는 경우 *
다음과 같은 작업을 수행 할 수 있습니다.
perl -e 'opendir($d,"."); unlink grep{/(\d+)\.end/ && $1 % 12 != 0} readdir($dir)'
속도와 관련하여 다음은이 접근법과 다른 답변 중 하나에서 제공되는 쉘을 비교 한 것입니다.
$ touch file.{01..64}.name.{00001..01000}.end
$ ls | wc
64000 64000 1472000
$ time for f in ./* ; do file="${f%.*}"; if [[ $((10#${file##*.} % 12)) -ne 0 ]]; then rm "$f"; fi; done
real 2m44.258s
user 0m9.183s
sys 1m7.647s
$ touch file.{01..64}.name.{00001..01000}.end
$ time perl -e 'unlink grep{/(\d+)\.end/ && $1 % 12 != 0}@ARGV;' *
real 0m0.610s
user 0m0.317s
sys 0m0.290s
당신이 볼 수 있듯이, 그 차이는 엄청나 다 예상대로 .
설명
- 은
-e
단순히 말하고perl
명령 행에 주어진 스크립트를 실행합니다. @ARGV
스크립트에 제공된 모든 인수를 포함하는 특수 변수입니다. 우리는 그것을 제공하기 때문에*
현재 디렉토리의 모든 파일과 디렉토리를 포함합니다.-
는
grep
파일 이름의 목록을 검색하고 숫자의 문자열 점과 일치하는 모든 찾습니다end
(/(\d+)\.end/)
. -
숫자 (
\d
)는 캡처 그룹 (괄호)에 있으므로로 저장됩니다$1
. 그러면grep
그 숫자가 12의 배수인지 확인하고 그렇지 않으면 파일 이름이 반환됩니다. 즉, 배열@bad
은 삭제할 파일 목록을 보유합니다. -
그런 다음 목록이 전달되어
unlink()
파일은 제거되지만 디렉토리는 제거되지 않습니다.
답변
파일 이름이 형식 인 file.00064.name.99999.end
경우 먼저 번호를 제외한 모든 항목을 잘라 내야합니다. 이를 위해 for
루프를 사용합니다 .
우리는 또한 Bash 셸에 10을 사용하도록 지시해야합니다 .Bash 산술은 0으로 시작하는 숫자를 8로 처리하므로 문제가 발생합니다.
파일을 포함하는 디렉토리에서 시작할 때 스크립트로 사용하려면 다음을 사용하십시오.
#!/bin/bash
for f in ./*
do
if [[ -f "$f" ]]; then
file="${f%.*}"
if [[ $((10#${file##*.} % 12)) -ne 0 ]]; then
rm "$f"
fi
else
echo "$f is not a file, skipping."
fi
done
또는이 매우 추한 명령을 사용하여 동일한 작업을 수행 할 수 있습니다.
for f in ./* ; do if [[ -f "$f" ]]; then file="${f%.*}"; if [[ $((10#${file##*.} % 12)) -ne 0 ]]; then rm "$f"; fi; else echo "$f is not a file, skipping."; fi; done
모든 부분을 설명하려면 :
for f in ./*
현재 디렉토리의 모든 것을 의미합니다. do …. 이렇게하면 각 파일 또는 디렉토리를 변수 $ f로 설정합니다.if [[ -f "$f" ]]
찾은 항목이 파일인지 확인합니다. 그렇지 않으면 해당echo "$f is not...
부분으로 건너 뛰므로 실수로 디렉토리를 삭제하지 않습니다.file="${f%.*}"
$ file 변수를 파일 이름으로 마지막 뒤에 오는 모든 것을 잘라냅니다.
.if [[ $((10#${file##*.} % 12)) -eq 0 ]]
기본 산술이 시작되는 위치입니다. 확장명을 사용하지 않으면 파일 이름${file##*.}
의 마지막 부분보다 먼저 모든 항목을 다듬습니다.
.$(( $num % $num2 ))
는 Bash 산술이 모듈로 연산을 사용하는 구문이며10#
, 시작시 Bash 가베 이스 10을 사용하여 성가신 선행 0을 처리하도록 지시합니다.$((10#${file##*.} % 12))
그런 다음 파일 이름 번호의 나머지를 12로 나눕니다.-ne 0
나머지가 “같지 않은”지 여부를 확인합니다.- 나머지가 0이 아닌 경우, 파일이 함께 삭제
rm
명령, 당신은 대체 할 수rm
와 함께echo
먼저 예상되는 파일을 삭제할 수 있는지 확인하려면 다음을 실행하는 경우.
이 솔루션은 재귀 적이 지 않으므로 현재 디렉토리의 파일 만 처리하며 하위 디렉토리로 이동하지 않습니다.
디렉토리에 대해 경고 if
하는 echo
명령 이있는 명령문 은 디렉토리 rm
자체에 대해 불평하고 삭제 하지 않기 때문에 실제로는 필요 하지 않습니다.
#!/bin/bash
for f in ./*
do
file="${f%.*}"
if [[ $((10#${file##*.} % 12)) -ne 0 ]]; then
rm "$f"
fi
done
또는
for f in ./* ; do file="${f%.*}"; if [[ $((10#${file##*.} % 12)) -ne 0 ]]; then rm "$f"; fi; done
제대로 작동합니다.
답변
Bash 대괄호 확장을 사용하여 12 번째 숫자마다 이름을 생성 할 수 있습니다. 테스트 데이터를 만들어 봅시다
$ touch file.{0..9}{0..9}{0..9}{0..9}{0..9}.end # create test data
$ mv file.00024.end file.00024.end.name.99999.end # testing this form of filenames
그럼 우리는 다음을 사용할 수 있습니다
$ ls 'file.'{00012..100..12}* # print these with numbers less than 100
file.00012.end file.00036.end file.00060.end file.00084.end
file.00024.end.name.99999.end file.00048.end file.00072.end file.00096.end
$ rm 'file.'{00012..100000..12}* # do the job
많은 양의 파일에 대해 절망적으로 느리게 작동합니다. 수천 개의 이름을 생성하는 데 시간과 메모리가 필요하므로 실제 효율적인 솔루션보다 더 트릭입니다.
답변
조금 길지만 내 마음에 온 것입니다.
for num in $(seq 1 1 11) ; do
for sequence in $(seq -f %05g $num 12 99999) ; do
rm file.$sequence.end.99999;
done
done
설명 : 매 12 번째 파일을 11 번씩 삭제하십시오.
답변
모든 겸손에서이 솔루션은 다른 답변보다 훨씬 훌륭하다고 생각합니다.
find . -name '*.end' -depth 1 | awk 'NR%12 != 0 {print}' | xargs -n100 rm
약간의 설명 : 먼저로 파일 목록을 생성합니다 find
. 이름이 끝나는 모든 파일을 얻습니다..end
깊이가 1 (즉, 하위 폴더가 아닌 작업 디렉토리에 직접 있습니다. 하위 폴더가없는 경우 제외 할 수 있음). 출력 목록은 알파벳순으로 정렬됩니다.
그런 다음 해당 목록을으로 파이프합니다 awk
. 여기서 NR
행 번호 인 특수 변수 를 사용합니다 . 우리는 어디에 파일을 인쇄하여 모든 12 번째 파일을 제외합니다 NR%12 != 0
. awk
명령을 단축 할 수 awk 'NR%12'
모듈로 연산자의 결과는 부울 값으로 해석됩니다 그리고이 때문에 {print}
암시 어쨌든 이루어집니다.
이제 xargs와 rm을 사용하여 삭제할 수있는 파일 목록을 만들었습니다. 표준 입력을 인수로 사용 xargs
하여 지정된 명령 ( rm
)을 실행합니다 .
파일이 많으면 ‘인수 목록이 너무 깁니다'(제한이 256 kB이고 POSIX에 필요한 최소값이 4096 바이트 임)와 같은 오류가 발생합니다. 이것은 -n 100
플래그 로 피할 수 있습니다. 플래그는 인수를 100 단어마다 나누고 (파일 이름에 공백이있는 경우주의해야 할 것) rm
100 개의 인수 만 가진 별도의 명령을 실행합니다 .
답변
bash 만 사용하는 첫 번째 방법은 다음과 같습니다. 1. 유지하려는 모든 파일을 다른 디렉토리 (예 : filename의 숫자가 12의 배수 인 모든 파일)로 이동 한 다음 2. 디렉토리의 나머지 파일을 모두 삭제하십시오. 그런 다음 3. 여러 개의 파일을 원래 위치로 되돌려 놓습니다. 따라서 다음과 같이 작동 할 수 있습니다.
cd dir_containing_files
mkdir keep_these_files
n=0
while [ "${n}" -lt 99999 ]; do
padded_n="`echo -n "00000${n}" | tail -c 5`"
mv "filename${padded_n}.end" keep_these_files/
n=$[n+12]
done
rm filename*.end
mv keep_these_files/* .
rmdir keep_these_files