アーカイブしたいディレクトリのリストがあります。しかし、時にはそれらがすべて存在しない場合があります。
ディレクトリリストを提供してアーカイブを作成できるようにしたいのですが、これは既存のディレクトリのみをアーカイブし、見つからないディレクトリは無視します。 (ただし、ディレクトリが存在しない場合はまだ失敗します)
これは、継続的な統合を実行しており、特定のプロセスが後で使用するためにアーカイブにアーカイブしたい特定の成果物を生成するため、私にとって効果的です。生成できる可能性のあるすべてのパスを知っていますが、どのパスが何であるかは必ずしもわかりません。作られた。
可能なパスは次のとおりです。here_is_a_dir
here_is_another_one
yet_another_dir
私は通常、次のコマンドを使用してアーカイブを作成します。
tar -czf archive.tgz here_is_a_dir here_is_another_one yet_another_dir
もちろん、ディレクトリが見つからない場合は失敗します。
理想的には単純なコマンドでなければならず、完了するためにスクリプトは必要ありません。 (具体的には私の環境でのみ可能なので、他の人のように派手なシェルは使えませんが、sh
これbash
は私の環境によって異なり、これから変わることもあるので、他のシェルを使う答えもとても良いようです。)
答え1
使用される出力はls
通常賢明ではなく安全ではありません。スペースや改行だけでなく、他のシェルメタ文字もファイル名やディレクトリ名で有効な文字であることを覚えておいてください。この問題は多くの場合に解決できますが、これを行うには通常、find
作業に適したツール(たとえば)を使用するよりも多くの労力が必要です。
だからfind
代わりにそれを使用してください。たとえば、
find . -maxdepth 1 -type d \( -name here_is_a_dir -o -name here_is_another_one \
-o -name yet_another_dir \) -exec tar cfz archive.tgz {} +
-type d
これは、現在のディレクトリ()で一致するディレクトリ()を見つけ、.
それをtar
コマンドの引数として使用します。 toはORを使用\(
して\)
各サブ式を結合する式です-o
(デフォルトでは、findの述語はAND結合です)。つまり、「最大深さ1 AND型ディレクトリAND(dir1 OR dir2 OR dir3)」と読み出されます。
優先順位を強制する括弧がない場合は、「最大深度 1 AND 型ディレクトリ AND dir1 OR(dir2 OR dir3)」と解釈され、既存のディレクトリの完全なリストは返されません。ほとんどの場合、dir1が存在するかどうかに応じて何も返さないか、dir3のみが返されます。
現在のディレクトリの下のサブディレクトリを見つけるには、この-maxdepth 1
パラメータを削除します。
ディレクトリ一致で大文字と小文字を区別しない場合は、-iname
代わりにを使用してください-name
。-name
orの引数は-iname
固定文字列ではなくパターンにすることができます。これは、必要なディレクトリ名が非常に似ている場合に便利です。例えば
find . -maxdepth 1 -type d -iname 'dir[123]' -exec tar cfz archive.tgz {} +
これは-exec ....
パイプtoと非常によく似ていますxargs
が、toに組み込まれていますfind
。実際にxargs
したい場合はすべて-exec
を-print0 | xargs -0 -r tar cfz archive.tgz
。例えば
find . -maxdepth 1 -type d -iname 'dir[123]' -print0 | \
xargs -0 -r tar cfz archive.tgz
(これはNUL文字を出力区切り文字として使用するため、スペースなどを含むディレクトリ名と一緒に使用するのが安全です。-exec
この-r
オプションは、入力がなければxargsに何もしないように指示します)
答え2
そしてzsh
:
dirs_to_archive=(some/dir /some/other/dir and/more/dirs)
existing_dirs=($^dirs_to_archive(/N))
if (($#existing_dirs)); then
tar -cf - -- $existing_dirs | xz > file.tar.xz
else
echo >&2 Error: none of the dirs were found
fi
POSIX対応するコマンド(ただし、POSIXコマンドでもtar
POSIXxz
コマンドでもない)は、次のようになります。
# The list of dirs in "$@" (the only array in POSIX sh language)
set -- some/dir /some/other/dir and/more/dirs
for dir do
# remove from the array the elements that are not directories like with
# zsh's / glob qualifier above
[ -d "$dir" ] && [ ! -L "$dir" ] && set -- "$@" "$dir"
shift
done
if [ "$#" -gt 0 ]; then
tar -cf - -- "$@" | xz > file.tar.xz
else
echo >&2 Error: none of the dirs were found
fi
答え3
Bashにアクセスできる場合は、拡張ワイルドカード(extglob
)を使用してください。
$ shopt -s extglob; set -x
$ tar -czf archive.tgz *(here_is_a_dir|here_is_another_one|yet_another_dir)
+ tar -czf archive.tgz
tar: no files or directories specified
次のいずれかが存在する場合:
$ touch here_is_a_dir yet_another_dir
+ touch here_is_a_dir yet_another_dir
$ tar -czvf archive.tgz *(here_is_a_dir|here_is_another_one|yet_another_dir)
+ tar -czvf archive.tgz here_is_a_dir yet_another_dir
a here_is_a_dir
a yet_another_dir
set -x
(グローブ拡張結果を確認するために使用しました。)
答え4
POSIX sh()でのみtar.sh
使用する必要があるもの:
#!/bin/sh
first=1
for dir in "$@"; do
if [ "$first" ]; then # this is a bit ugly
set --
first=
fi
if [ -d "$dir" ]; then
set -- "$@" "$dir"
fi
done
echo tar -czf archive.tar.gz "$@" # remove that 'echo'
テスト:
$ mkdir here_is_a_dir yet_another_dir
$ ./tar.sh here_is_a_dir here_is_another_one yet_another_dir
tar -czf archive.tar.gz here_is_a_dir yet_another_dir