ディレクトリにファイルのアーカイブ(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[$@]
答え1
この問題を解決するには、2つの主な問題があります。ユーザーが指定した特定のファイル名サフィックスを含むすべてのファイルを見つけてアーカイブに追加する必要がありますtar
。
このfind
コマンドには-name
使用したいオプションがありますが、単一のファイル名パターンのみを使用します。スクリプトユーザーは複数のファイル名のサフィックスを提供するため、サフィックスの数と同じ数の-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 \( "$@" \)
これは$@
、コマンドラインで指定されたサフィックスが最初からすでに含まれている配列を変更します。ループから前の要素を削除し$@
、配列の末尾に単語を挿入します。
このスクリプトが呼び出されると
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" {} +
上記のスクリプトで引用符を使用したのは意図的なものです。スペース、改行、その他の珍しい文字を含む名前など、許可されたファイル名を使用してファイルをアーカイブできます。
関連:
find
を含む実装を使用している場合は、次のスクリプトに示すように、見つかった-print0
パス名を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
GNUがオプションを使用して読み取ることができるfind
nulで区切られたパス名が出力されます。tar
--null -T -
bash
特定のスクリプトとしての最後のスクリプト(配列をオプションnames
として使用-name
):
#!/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 -
答え2
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修飾子:隠しファイルを含み、通常のファイルのみを選択します。