このアーカイブスクリプトを実行すると「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隠しファイルを含めるためには、対応する1つの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(および以前のすべてのディレクトリコンポーネント)が存在しない場合にのみディレクトリが作成され、戻り時にディレクトリが存在しない場合にのみ失敗します。

ここでは、最初の点と2番目の点を組み合わせると、gzipこのエラーが返されます。

ループは値(例えば)を介して繰り返されますfind $BASE -maxdepth...。を引用することを忘れてしまったので、$i分割+globが影響をgzip $i受け、デフォルトはの内容に別の引数として渡されます。$i$IFSgzipfind$BASE-maxdepth...$i

GNUユーティリティには、オプションではなく引数の後にオプションが認識されるバグ機能があります(これは区切り文字を忘れないことがより重要です--)。-maxdepthしたがって、オプションとして処理され、gzipアルファベットオプションとして単一のグループとして処理されます。だから同じ-m -a -x -d...

-m現在文書化されていないオプションであり、修正時間を知らせたり保存したりせず、gzipUnixgunzipシリーズ-aシステムでも文書化されておらず、略語は--asciiMicrosoft Windowsにのみ関連し(名前は多少誤解を招くことがあります)、-xサポートされているオプションには含まれません。文書化されていなくても、このエラーが発生します。

おすすめ記事