アーカイブしたいディレクトリのリストがあります。しかし、すべてが存在するわけではありません。
ディレクトリのリストを提供することによってアーカイブを作成できるようにしたいのですが、それは既存のものだけをアーカイブし、欠落しているものは無視します。 (ただし、ディレクトリが存在しない場合でも失敗するはずです)
継続的インテグレーションを実行していて、一部のプロセスが特定のアーティファクトを作成してアーカイブに将来保持したいので、これは私にとって便利です。作成されます。
可能なパスは次のとおりです: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
などのファンシーなシェルは使用できませんが、これは私の環境に固有であり、将来変更される可能性があります。他のシェルを使った答えもおそらく良いと思います。)
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
コマンドの引数として使用します。 _\(
_から_\)
_は、_-o
_を使用して各部分式がORで結合された式です(デフォルトでは、findの述語はANDで結合されます)。つまり、「maxdepth 1 ANDタイプディレクトリAND(dir1 OR dir2 OR dir3)」として読み取られます。
優先順位を強制する括弧がないと、「maxdepth 1 ANDタイプディレクトリAND dir1 OR(dir2 OR dir3)」と解釈され、既存のすべてのディレクトリの完全なリストを返さないほとんどの場合、dir1が存在するかどうかに応じて、何も返さないか、dir3のみを返します。
現在のディレクトリの下にあるサブディレクトリを見つけるには、_-maxdepth 1
_引数を削除します。
ディレクトリの一致で大文字と小文字を区別しない場合は、_-iname
_ではなく_-name
_を使用します。 _-name
_または_-iname
_の引数は、固定文字列ではなくパターンにすることができます。これは、目的のディレクトリ名が非常に似ている場合に便利です。例えば.
_find . -maxdepth 1 -type d -iname 'dir[123]' -exec tar cfz archive.tgz {} +
_
_-exec ....
_はxargs
へのパイプとよく似ていますが、find
に組み込まれています。実際、_-exec
_以降のすべてを_-print0 | xargs -0 -r tar cfz archive.tgz
_で置き換える場合は、xargs
を使用できます。例えば.
_find . -maxdepth 1 -type d -iname 'dir[123]' -print0 | \
xargs -0 -r tar cfz archive.tgz
_
(これは出力セパレータとしてNUL文字を使用するため、_-exec
_を使用するのと同じように、スペースなどを含むdirnameで使用しても安全です。_-r
_オプションは、xargsに何も実行しないように指示します入力)
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(tar
もxz
もPOSIXコマンドではないことに注意してください)は次のようになります。
# 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
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
そして、それらの1つ以上が存在する場合:
$ 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
なので、グロブ拡張の結果を確認できます。)
これは、ls
を使用して既存のディレクトリのリストを作成し、xargs
を介してtar
コマンドにパイプすることで比較的簡単に実行できます。
ソリューション:
ls -d here_is_a_dir here_is_another_one yet_another_dir 2> /dev/null | xargs tar -czf archive.tgz
内訳:
ls -d
ディレクトリのみを一覧表示here_is_a_dir here_is_another_one yet_another_dir
チェックするディレクトリのリスト2> /dev/null
stderrを/ dev/nullにパイプして、stdout出力のみを取得します(dirsが欠落していない)| xargs
は、前のコマンドの既存のディレクトリのリストを引数に変換しますtar -czf archive.tgz
引数を使用してアーカイブを作成しますtar
のバージョンがサポートしている場合は、空のtarファイルを作成し、-r
ではなく-c
を使用して、必要に応じて追加します。
touch foo.tar
for d in here_is_a_dir here_is_another_one yet_another_dir; do
if [ -d "$d" ]; then
tar -rf foo.tar "$d"
fi
done
gzip foo.tar
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
pax がある場合、これを使用して、アーカイブに含まれるものをフィルタリングできます。 Paxは、歴史的に多様なcpioとtarの代替としてPOSIXによって義務付けられていますが、多くのUnixバリアントはその採用に抵抗しており、特にBusyBoxには採用されていません。
Paxには、ファイルの除外機能がありますが、説明では隠されています。 -s
を使用してファイルの名前を変更できます。ファイルの名前を空の文字列に変更すると、そのファイルは除外されます。複数の-s
オプションを使用すると、最初の一致ごとに適用され、-s
フィルターの名前変更はスキップされます。このようにして、一連の包含/除外ルール rsyncと同様 を構築できます。 Pax構文の包含規則は-s'!REGEX!&!'
(それ自体に名前変更)であり、除外規則は-s'!REGEX!!'
(空に名前変更)です。
pax -w -x ustar \
-s'!^\./here_is_a_dir$!&!' -s'!^\./here_is_a_dir/!&!' \
-s'!^\./here_is_another_one$!&!' -s'!^\./here_is_another_one/!&!' \
-s'!^\./yet_another_dir$!&!' -s'!^\./yet_another_dir/!&!' \
. | gzip >archive.tgz
BSD tarには、同様の-s
オプションがあります。一方、GNU= tarとBusyBox tarには、これを行う/体操を除外する方法がありません。
最も単純なのはおそらく
find adir anotherdir yadir -maxdepth 0 2>&- | tar Tcf - my.tar