이 아카이브 스크립트를 실행할 때 "gzip: 잘못된 옵션 -- 'x'" 오류 발생

이 아카이브 스크립트를 실행할 때 "gzip: 잘못된 옵션 -- 'x'" 오류 발생

이 스크립트는 특정 디렉터리에서 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)부분은글로벌 예선, 이는 글로벌 확장에 추가로 적합합니다.

  • Nnullglob일치하는 항목이 없을 경우 오류를 반환하는 대신 glob이 빈 상태로 확장되도록 해당 glob 하나에 만 적용됩니다 . 일반적으로 for 루프 목록에서 이것을 사용하려고 합니다.
  • D숨겨진 파일을 포함하기 위해 해당 하나의 glob에서만 작동합니다 dotglob(기본적으로 수행되는 것과 동일 find)
  • LM+20findGNU 해당 -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부터 파일에서 파일 목록 전달을 지원합니다.-()!findfind -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$IFSgzipfind$BASE-maxdepth...$i

GNU 유틸리티에는 옵션이 아닌 인수 후에도 옵션이 인식되는 버그 기능이 있습니다(이로 인해 구분 기호를 잊지 않는 것이 더욱 중요함 --). -maxdepth따라서 옵션으로 처리되고 gzip알파벳 옵션으로 단일 그룹으로 처리됩니다. 그래서 같은 -m -a -x -d...

-m현재 문서화되지 않은 옵션이고, 수정 시간을 알려주 gzip거나 gunzip보존하지 않으며, -aUnix 계열 시스템에서도 문서화되지 않고, 약어는 --asciiMicrosoft Windows에만 관련되며(이름은 다소 오해의 소지가 있습니다), -x지원되는 옵션에 포함되지 않으며, 심지어 문서화되어 있지도 않아서 이런 오류가 발생합니다.

관련 정보