cpの対話型オプションを使用してstdinでテキストを保存する

cpの対話型オプションを使用してstdinでテキストを保存する

対話型シェルスクリプトでコマンドの出力をファイルに保存したいと思います。

$ echo "Hello, World" > test.txt

ただし、test.txtがすでに存在する場合は上書きしないでください。だから活用すればいいと思います。CPそれとの対話オプション(CP-i) 対象ファイルが存在することを確認してください。私はこれを試しました:

$ echo -n "Hello" | cp -i /dev/stdin test.txt 

test.txtがまだ存在しない場合はtest.txtに "Hello"が記録されますが、test.txtが存在するとcpはこのパイプから上書き応答のみを読み取るため、コピーは中断されます。

しかし、

$ cp -i <(echo "World") test.txt
cp: overwrite 'test.txt'? y
'/proc/self/fd/11' -> 'test.txt'

期待どおりに動作します。 cpは、子プロセスのファイル記述子をソースとして使用してtest.txtにcp'iedするようです。理由は全くわかりません。

どんなアイデア、説明、またはより良い方法がありますか?

答え1

代わりに別のファイル記述子を使用してください。/dev/stdin

echo Hello | { cp -i /dev/fd/5 test.txt 5<&0 </dev/tty; }

あるいは、yes(1)を介してスクリプトを作成することもできます。

{ echo Hello | { cp -i /dev/fd/5 test.txt 5<&0 <&4; }; } 4<&0

2つのバリエーションの中で非標準の問題を解決するには、zshでのみ追加の{ ... }サラウンドが必要です。cp -i ...複数のオペレーティングシステム特徴。

これは、/dev/fd/Nすべての標準シェルとファイルをサポートするすべてのシステムで機能する必要があります。ただし、Linux + ksh93の組み合わせは除外されます。これは、ksh93がLinuxで開くことができないパイプを実装するためにUnixソケットを使用するため、機能しません(動作/dev/fd/Nしない)echo | cat /dev/stdin

そこにファイルを入れないと、echo -n "Hello" | cp -i /dev/stdin test.txt実際にファイルが破損します。これがあなたがそれに頼ってはならない理由の1つです。"Hello""You suck!"cp -i

答え2

このようなシェルは、bashすでにリダイレクトを介してファイルを上書きするのを防ぎます。

set -o noclobber
echo hello >world
echo hello >world
-bash: world: cannot overwrite existing file

上書きする前にユーザーに尋ねることができるようにするには、設定のnoclobber代わりにこのようなものを使用します。

#!/bin/bash

# Define function sureYN  [<prompt>]  <target>
sureYN() {
    local prompt="$1" target="$2" yn='y'
    [[ -z "$target" ]] && { target="$prompt"; prompt="Overwrite $target"; }

    [[ -f "$target" && -t 0 ]] && read -p "$prompt (y/n)? " yn >&2
    [[ "$yn" =~ ^[Yy] ]]
}

sureYN /tmp/first && cp -fp /etc/hosts /tmp/first
sureYN "Can I replace /tmp/second" /tmp/second && echo this is the second >/tmp/second

関連情報