ターゲットが存在する場合は、cpにエラー値を返します。

ターゲットが存在する場合は、cpにエラー値を返します。

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仕様の一部ではない-nonフラグが必要です。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をチェックするのではなく、ファイルがパスにまだ存在することを確認することです$tmpmv -n ...成功すればいけません。 ($tmp損失を確認する前に他のプロセスが新しく作成されなかった場合。)

$target効率のために、ルーチンの先頭に存在するかどうかチェックを追加することをお勧めします。存在することがわかったら、コピーを作成して移動しようとした後に失敗したことを確認し、コピーを削除するのではなくすぐに失敗することがあります。以下は(簡単な)練習です。

答え4

次のことができます。

(set -C &&  cat < /path/to/src > /path/to/dest)

cpただし、ファイルの内容(一部の実装などの権限、所有権、またはスパースを除く)以外は何もコピーしません。

関連情報