cp
ターゲットファイルがすでに存在する場合(LinuxのGNU coreutilsで)ゼロ以外の値を返す方法はありますか?
それとも、この機能を提供する一般的に使用される他の小さなユーティリティはありますか?
これは、シェルスクリプトで誤って何も失うことなく、ユーザーの対話なしでファイルを自動的にコピーするのに役立ちます。コピーをオリジナルと比較すると同様の結果が得られますが、より簡単な解決策があることを願っています。
答え1
一部のcp
実装(GNUを含む)には、ファイルが存在する場合にファイルを破壊しないcp
非標準スイッチがあります。-n
しかし、GNUはcp
とにかく戻ります。0
シェルスクリプトでは、ifステートメントを使用してファイルの内容をコピーする前にファイルが存在するかどうかをテストできます。
if [ -e /path/to/file ]
then
exit 1
else
cp file /path/to/file
fi
または、機能が必要な場合は、次のように使用できます。
function cpa(){
if [ -e "$2" ]
then
exit 1
else
/bin/cp "$1" "$2"
fi
}
答え2
次のシェルフラグメントは、ターゲットが存在しない場合にのみファイルをコピーし、ターゲットが存在する場合はゼロ以外の状態を返します。
(set -C; : >"$target" && cp -- "$source" "$target")
これは原子的ではありません。$target
破棄しようとした後にコピーが開始される前にファイルが作成された場合は、上書きされます。さらに、cp
これは原子的ではありません。他のプロセスがファイルが作成されるのを観察できます。ただし、すべての同時作成者が同じ戦略を使用している場合は正しく機能します。
次のより複雑なコードスニペットは、最初に一時コピーを作成してからその場所に移動します。それでも競争条件があります。実行されていない関連のないプログラムがオブジェクトファイルを生成できる小さな時間枠があります。
( set -C
tmp=$(mktemp -p "$(dirname -- "$target")")
cp -- '$source" "$tmp"
if : >"$target"; then
mv -i -- "$tmp" "$target"
else
rm -- "$tmp"
false
fi
)
答え3
h3rrmillerの答えに対する私の意見を広げ、Gillesの彫刻パターンに従うことは、一時的なコピーを作成してから所定の位置に移動する別の方法です。私はこのアプローチが競争条件の影響を受けないと思います。 POSIX仕様の一部ではない-n
onフラグが必要です。mv
しかし、広く使用されているようです。 (GNUの実装とBusyBox、FreeBSD、OS Xで検証されました。)
(
tmp=$(mktemp "${target}.XXXXXX") && # "mktemp -p" doesn't work on BSD
cp -- "$source" "$tmp" && # you may want to add -p flag
inode=$(ls -di "$tmp" | cut -d' ' -f1) && # see comment below
mv -n -- "$tmp" "$target" && # won't overwrite, but doesn't then exit non-0
if [ "$(ls -di "$target" | cut -d' ' -f1)" != "$inode" ]; then
rm -- "$tmp"; false
fi
)
stat -c'%i' "$tmp"
Linuxでは、以下を使用してinodeを取得できます。それはポータブルではありません。。
別のアイデアは、inodeをチェックするのではなく、ファイルがパスにまだ存在することを確認することです$tmp
。mv -n ...
成功すればいけません。 ($tmp
損失を確認する前に他のプロセスが新しく作成されなかった場合。)
$target
効率のために、ルーチンの先頭に存在するかどうかチェックを追加することをお勧めします。存在することがわかったら、コピーを作成して移動しようとした後に失敗したことを確認し、コピーを削除するのではなくすぐに失敗することがあります。以下は(簡単な)練習です。
答え4
次のことができます。
(set -C && cat < /path/to/src > /path/to/dest)
cp
ただし、ファイルの内容(一部の実装などの権限、所有権、またはスパースを除く)以外は何もコピーしません。