ディレクトリにファイルのアーカイブ(tar)を作成するbashスクリプトを作成しようとしています。このようにbashスクリプト(./backup.bash pdf txt bak)を呼び出すときは、ファイル拡張子を引数として渡す必要があります。私はそれらの引数を格納するために配列を使用しています。 (ls | grep -i {array})は、配列に入力されたファイル拡張子に一致するディレクトリ内のすべてのファイルを検索し、見つかったファイルを一覧表示します。 (find .-type)は、これらの拡張子を使用して、拡張子に関連付けられているファイルを検索します。 (tar cvf)は、backup.tarという名前で作業ディレクトリにバックアップファイルを作成しています。 tarコマンドの最後に配列をリストしましたが、今考えてみると、findコマンドをtarコマンドにパイプできるかもしれません。
my_array=([$@])
ls | grep -i \{my_array[$@]}
find . -type f \( -name "my_array[$@]" \)
tar cvf ./PATH/backup.tar my_array[$@]
この問題を解決するには、2つの主要な問題があります。ユーザーが指定した特定のファイル名サフィックスを持つすべてのファイルを検索し、それらをtar
アーカイブに追加する必要があります。
find
コマンドには正しく使用したい-name
オプションがありますが、使用できるファイル名パターンは1つだけです。スクリプトのユーザーが複数のファイル名サフィックスを指定しているため、サフィックスと同じ数の-name
オプションを使用する必要があります。
これは、いくつかの-name "PATTERN"
オプションの配列を作成する必要があることを意味し、それぞれの間に-o
があります(それらの間の論理「OR」を示します)。次に、これをfind
とともに使用して、指定されたファイル名のサフィックスのいずれかを持つファイル名を検索します。
以下は、配列$@
を変更することによってそれを行います。
#!/bin/sh
for suffix do
shift
set -- "$@" -o -name "*.$suffix"
done
shift # remove the very first "-o" from $@
find . -type f \( "$@" \)
これにより、$@
配列が変更されます。この配列には、最初から、コマンドラインで指定されたサフィックスがすでに含まれています。ループでは、$@
からfront要素を削除し、配列の最後に単語を挿入します。
このスクリプトを次のように呼び出す場合
sh script.sh sh txt c
と同等のfind
コマンドを作成します
find . -type f \( -name '*.sh' -o -name '*.txt' -o -name '*.c' \)
これにより、関連するすべてのファイルが検索されます。今、私たちはそれらをアーカイブに追加する必要があります。
GNU tar
(ただし、BSD tar
などではありません)を使用すると、r
アクションでアーカイブを更新または作成します(BSD tar
は更新のみを行い、新しいアーカイブは作成しません)。
backup=./PATH/backup.tar
rm -f "$backup"
find . -type f \( "$@" \) -exec tar -r -v -f "$backup" {} +
これにより、関連するファイルを含むアーカイブ./PATH/backup.tar
が作成されます。
tar -c
を使用しない理由は、このようにtar
からfind
を呼び出すと、tar
が複数回呼び出される可能性があるためです。 tar -c
を使用して新しいアーカイブを作成した場合、そのアーカイブはtar
が呼び出されるたびに切り捨てられます(find
が数千のファイルを検出した場合は何度も発生する可能性があります)。代わりにtar -r
を使用して、代わりにアーカイブを更新し続けます。
したがって、完全なスクリプトはおそらく次のようになります。
#!/bin/sh
backup=./PATH/backup.tar
if [ "$#" -eq 0 ]; then
echo 'No filename suffixes given' >&2
exit 1
fi
for suffix do
shift
set -- "$@" -o -name "*.$suffix"
done
shift # remove the very first "-o" from $@
rm -f "$backup"
find . -type f \( "$@" \) -exec tar -r -v -f "$backup" {} +
上記のスクリプトでの引用符の使用は非常に慎重であることに注意してください。スペース、改行、その他の異常な文字を含む名前を含む、許可されたファイル名でファイルをアーカイブすることが可能になります。
関連:
-print0
を持つfind
実装を使用する場合は、以下のスクリプトのように、見つかったパス名をGNU tar
に渡すこともできます。
#!/bin/sh
backup=./PATH/backup.tar
if [ "$#" -eq 0 ]; then
echo 'No filename suffixes given' >&2
exit 1
fi
for suffix do
shift
set -- "$@" -o -name "*.$suffix"
done
shift # remove the very first "-o" from $@
find . -type f \( "$@" \) -print0 | tar -c -v -f "$backup" --null -T -
-print0
を使用すると、find
はnulで区切られたパス名を出力し、GNU tar
は--null -T -
オプションで読み取ります。
bash
固有のスクリプトとしての最後のスクリプト(配列を使用、-name
オプションにはnames
):
#!/bin/bash
backup=./PATH/backup.tar
if [ "$#" -eq 0 ]; then
echo 'No filename suffixes given' >&2
exit 1
fi
names=( -name "*.$1" )
shift
for suffix do
names+=( -o -name "*.$suffix" )
done
find . -type f \( "${names[@]}" \) -print0 | tar -c -v -f "$backup" --null -T -
zsh
およびGNU tar
またはbsdtar
の場合:
_#! /bin/zsh -
set -o extendedglob
output=file.tar.gz
printf '%s\0' **/*.(${(j:|:)~${(b)@}})~$output(D.) |
tar --null -cf - -T - | xz > $output
_
${(b)@}
:位置パラメータを引用して、パターンとして使用されないようにします${(j:|:)...}
:結果の単語を_|
_と結合します${~var}
_:拡張をグロブパターンとして扱います(位置パラメーターがjpg
、gif
、_jpg|gif|\*
_の場合、現在は_*
_のように見えます)**/
_:任意のレベルのサブディレクトリpattern~$output
_:出力ファイル自体をglob展開から除外します(D.)
_:glob qualifiers:隠しファイルを含め、通常のファイルのみを選択します。