Verwenden der interaktiven Option von cp zum Speichern von Text aus stdin

Verwenden der interaktiven Option von cp zum Speichern von Text aus stdin

In einem interaktiven Shell-Skript möchte ich die Ausgabe eines Befehls in einer Datei speichern, wie in

$ echo "Hello, World" > test.txt

aber verhindern, dass test.txt überschrieben wird, wenn es bereits existiert. Daher dachte ich, es wäre eine gute Idee,cpmit seiner interaktiven Option (cp -ich), um zu prüfen, ob die Zieldatei existiert. Ich habe Folgendes versucht:

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

Dies schreibt „Hallo“ in test.txt, wenn test.txt noch nicht existiert, bricht das Kopieren jedoch ab, wenn test.txt existiert, da cp die Antwort auf die Frage, ob überschrieben werden soll oder nicht, nur aus dieser Pipe liest.

Dies

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

funktioniert wie vorgesehen, cp scheint den Dateideskriptor des Unterprozesses als Quelle zu nehmen und dieser wird in test.txt kopiert und ich weiß einfach nicht, warum.

Irgendwelche Ideen oder Erklärungen oder bessere Möglichkeiten, dies zu tun?

Antwort1

Verwenden Sie einen anderen Dateideskriptor anstelle von/dev/stdin

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

Oder weiterhin skriptfähig über yes(1)

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

In beiden Varianten werden die zusätzlichen { ... }around cp -i ...nur in zsh benötigt, um dessen nicht standardmäßigemultiosBesonderheit.

Dies sollte in jeder Standard-Shell und jedem System funktionieren, das Dateien unterstützt /dev/fd/N, mit Ausnahme der Kombination Linux + ksh93, die nicht funktioniert, da ksh93 Pipes mit Unix-Sockets implementiert, die unter Linux nicht geöffnet werden können /dev/fd/N(nicht einmal echo | cat /dev/stdinfunktionieren).

Sie echo -n "Hello" | cp -i /dev/stdin test.txtwerden die Datei tatsächlich zerstören, wenn Sie dort nichts anderes "Hello"angeben "You suck!". Das ist einer der Gründe, warum Sie sich nicht auf verlassen sollten cp -i.

Antwort2

Shells wie bashkönnen bereits vor dem Überschreiben von Dateien mit einer Umleitung schützen

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

Wenn Sie den Benutzer vor dem Überschreiben fragen möchten, würde ich anstelle der noclobberEinstellung so etwas verwenden

#!/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

verwandte Informationen