このスクリプトは、特定のディレクトリで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
隠しファイルを含めるためには、対応する1つの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
(および以前のすべてのディレクトリコンポーネント)が存在しない場合にのみディレクトリが作成され、戻り時にディレクトリが存在しない場合にのみ失敗します。
ここでは、最初の点と2番目の点を組み合わせると、gzip
このエラーが返されます。
ループは値(例えば)を介して繰り返されますfind $BASE -maxdepth...
。を引用することを忘れてしまったので、$i
分割+globが影響をgzip $i
受け、デフォルトはの内容に別の引数として渡されます。$i
$IFS
gzip
find
$BASE
-maxdepth...
$i
GNUユーティリティには、オプションではなく引数の後にオプションが認識されるバグ機能があります(これは区切り文字を忘れないことがより重要です--
)。-maxdepth
したがって、オプションとして処理され、gzip
アルファベットオプションとして単一のグループとして処理されます。だから同じ-m
-a
-x
-d
...
-m
現在文書化されていないオプションであり、修正時間を知らせたり保存したりせず、gzip
Unixgunzip
シリーズ-a
システムでも文書化されておらず、略語は--ascii
Microsoft Windowsにのみ関連し(名前は多少誤解を招くことがあります)、-x
サポートされているオプションには含まれません。文書化されていなくても、このエラーが発生します。