이 스크립트는 특정 디렉터리에서 20MB보다 큰 모든 파일을 압축하고 보관합니다.
#!/bin/bash
#Variables
BASE=/home/sengh/scripts
DEPTH=1 #how deep to go in the find operation
RUN=0
#Check if the directory is present or not
if [ ! -d $BASE ]
then
echo "directory does not exist: $BASE"
exit 1
fi
#Create 'archive' folder if not present
if [ ! -d $BASE/archive ]
then
mkdir $BASE/archive
fi
#Find the list of files larger than 20 MB
for i in 'find $BASE -maxdepth $DEPTH -type f -size +20M'
do
if [ $RUN -eq 0 ]
then
echo "[$(date "+%Y-%m-%d %H:%M:%S")] archiving $i ==> $BASE/archive"
gzip $i || exit 1
mv $i.gz $BASE/archive || exit 1
fi
done
다음과 같은 결과가 나타납니다.
[2024-01-26 23:55:06] 아카이브 검색 $BASE -maxlength $DEPTH -type f -size +20M ==> /home/sengh/scripts/archive gzip: 잘못된 옵션 -- 'x' `gzip을 시도하세요. --help'를 참조하세요.
gzip에 대한 매뉴얼 페이지를 탐색해 보았지만 "x"와 같은 옵션을 사용하지 않았기 때문에 도움이 되지 않았습니다. 도와주세요.
답변1
다음을 사용하는 것이 더 쉽습니다 zsh
.
#! /bin/zsh --
mkdir -p -- ~/scripts/archive || exit
PROMPT4='[%D{%F %T}] ' # for the xtrace output to be prefixed by the
# current time in [%F %T] strftime format
set -o xtrace -o noclobber # xtrace provides a trace of each command
# being executed. noclobber prevents
# redirection clobbering files.
for file (~/scripts/*(ND.LM+20))
gzip -c -- $file > ~/archive/scripts/$file.gz && rm -f -- $file || exit
이 (ND.LM+20)
부분은글로벌 예선, 이는 글로벌 확장에 추가로 적합합니다.
N
nullglob
일치하는 항목이 없을 경우 오류를 반환하는 대신 glob이 빈 상태로 확장되도록 해당 glob 하나에 만 적용됩니다 . 일반적으로 for 루프 목록에서 이것을 사용하려고 합니다.D
숨겨진 파일을 포함하기 위해 해당 하나의 glob에서만 작동합니다dotglob
(기본적으로 수행되는 것과 동일find
)LM+20
find
GNU 해당-size +20M
제한은 크기가 정수 메가바이트로 반올림되고 엄격하게 20보다 큰 파일, 즉 20971521바이트L
이상의 파일까지 확장됩니다..
좋아요는-type f
다음으로 제한됩니다.정기적인파일은 심볼릭 링크, fifo, 디렉터리, 장치 등 다른 유형의 파일만 제외합니다.
Bash를 사용하여 동일한 수준의 안정성으로 동일한 작업을 수행하는 것은 매우 번거롭고 최신 버전의 GNU 유틸리티가 필요합니다.
#! /bin/bash --
mkdir -p -- ~/scripts/archive || exit
PS4='[\D{%F %T}] ' # for the xtrace output to be prefixed by the
# current time in [%F %T] strftime format
set -o noclobber # prevents redirection clobbering files.
while IFS= read -rd '' -u3 file; do
(set -o xtrace
gzip -c -- "$file" > ~/archive/scripts/"$file".gz) &&
rm -f -- "$file"
) 3<&- || exit
done 3< <(
find -H -files0-from <(printf '%s\0' ~/scripts/archive) \
-mindepth 1 -maxdepth 1 -type f -size +20M -print0 |
sort -z
)
언제나처럼 당신은--
옵션이 아닌 매개변수와 옵션을 분리 해야 함로 시작하는 옵션이 아닌 인수가 options 로 처리되지 않는지 확인하세요 -
. 그러나 이는 도움이 되지 않습니다. 그 이후에도 (또는 , )로 시작 find
하면 여전히 술어로 간주되기 때문입니다 . --
BSD의 경우 대신 사용하면 되지만 GNU는 이를 지원하지 않습니다. 그러나 버전 4.9부터 파일에서 파일 목록 전달을 지원합니다.-
(
)
!
find
find -f "$dir"
find -- "$dir"
find
-f
-files0-from
코드에 대한 몇 가지 참고 사항:
- Bash에서는 매개변수 확장을 인용해야 합니다. 그렇지 않으면 분할+glob을 거치게 됩니다. 바라보다언제 큰따옴표가 필요합니까?이 주제에 대한 기타 많은 Q&A. shellcheck는 이런 종류의 초보자 실수를 잡는 데도 도움이 될 수 있습니다.
'...'
강력한 참조에 사용됩니다.'find ...'
리터럴 문자열입니다find ...
. 그러나 작은따옴표를 역따옴표( )로 바꾸더라도`...`
이는 여전히 잘못된 접근 방식입니다. 바라보다찾기 결과를 반복하는 것이 왜 나쁜 습관입니까?더 알아보기.if condition-not-met; then do-something-that-would-make-sure-the-condition-is-met; fi
당신과 같은 일은 피하는 것이 가장 좋습니다 .if [ ! -d ...]; then mkdir...
TOCTOU 경쟁 조건. 를 사용하면-p
디렉터리mkdir
(및 이전의 모든 디렉터리 구성 요소)가 존재하지 않는 경우에만 디렉터리가 생성되며 반환 시 디렉터리가 존재하지 않는 경우에만 실패합니다.
여기서는 첫 번째 점과 두 번째 점을 조합하면 gzip
이 오류가 반환됩니다.
루프는 값(예: )을 통해 반복됩니다 find $BASE -maxdepth...
. 를 인용하는 것을 잊어버렸기 때문에 $i
분할 +glob이 영향을 gzip $i
받고 기본값 은 의 내용에 별도의 인수 로 전달 됩니다 .$i
$IFS
gzip
find
$BASE
-maxdepth...
$i
GNU 유틸리티에는 옵션이 아닌 인수 후에도 옵션이 인식되는 버그 기능이 있습니다(이로 인해 구분 기호를 잊지 않는 것이 더욱 중요함 --
). -maxdepth
따라서 옵션으로 처리되고 gzip
알파벳 옵션으로 단일 그룹으로 처리됩니다. 그래서 같은 -m
-a
-x
-d
...
-m
현재 문서화되지 않은 옵션이고, 수정 시간을 알려주 gzip
거나 gunzip
보존하지 않으며, -a
Unix 계열 시스템에서도 문서화되지 않고, 약어는 --ascii
Microsoft Windows에만 관련되며(이름은 다소 오해의 소지가 있습니다), -x
지원되는 옵션에 포함되지 않으며, 심지어 문서화되어 있지도 않아서 이런 오류가 발생합니다.