Ich möchte cp
vor dem Überschreiben eine Bestätigung erhalten, daher verwende ich -i
.
(Ich verwende manchmal einen Alias für cp
oder ähnliches, sodass cp
es immer mit auftritt -i
.)
Ich möchte vielleicht „Alles überschreiben“ sagen. Ich weiß, dass das die Standardeinstellung ist, aber da ich verwende, -i
sehe ich das nicht.
Ich möchte problemlos die Antwort „Ja“ auf alle oder „Nein“ auf alle erhalten.
Ich frage nicht, wie man einen Alias umgeht, ich möchte das -i
.
Hier ist mein Versuch, ein „Ja“ zu erzwingen -i
.
~$ mkdir test1
~$ cd test1
~/test1$ mkdir smalls
~/test1$ touch a.a
~/test1$ touch b.b
~/test1$ cp -i ?.? smalls
~/test1$ cp -i ?.? smalls
overwrite smalls/a.a? (y/n [n]) y
overwrite smalls/b.b? (y/n [n]) y
~/test1$ yes|cp -i ?.? smalls
overwrite smalls/a.a? (y/n [n]) overwrite smalls/b.b? (y/n [n]) ~/test1$
~/test1$
~/test1$ yes ''|cp -i ?.? smalls
overwrite smalls/a.a? (y/n [n]) not overwritten
overwrite smalls/b.b? (y/n [n]) not overwritten
~/test1$
Ich schaffe es also, überall ein „y“ zu erzwingen, aber dann bekomme ich keine neuen Zeilen.
Wenn ich yes ''|
es versuche, wird kein „Ja“ gesendet.
Ich möchte auch ein „n“/„nein“ übergeben können.
Und da ich möglicherweise viele Dateien habe, möchte ich nicht jede Datei yEntereinzeln manuell eingeben.nEnter
Ich habe nichts gegen eine Lösung, die den Befehl nicht beinhaltet yes
.
Antwort1
Dies ist nicht so einfach, wie es scheint.
Analyse
Beim Ausführen cp -i
und Beantworten von Eingabeaufforderungen interaktiv yEnterstammt die neue Zeile, die Sie nach dem Eintippen erhalten, aus der Zeilendisziplin. Die Zeilendisziplin wird als Echo y
und als neue Zeile ausgegeben.
Sie können diesen Mechanismus beobachten, indem Sie sole cat
in einem Terminal ausführen. Wenn cat
auf eine Eingabe gewartet wird, können Sie eine lange Zeile eingeben und sogar Zeichen (mit Backspace) oder die ganze Zeile (mit Ctrl+ u) löschen; alles, was Sie sehen, wird von der Zeilendisziplin verarbeitet und cat
bleibt einfach ohne Eingabe stehen. Nur wenn Sie Enter(oder Ctrl+ m, oder Ctrl+ j) drücken, cat
wird die Zeile abgerufen und gedruckt. Die neue Zeile nach dem, was Sie eingegeben haben, stammt aus der Zeilendisziplin, die neue Zeile nach dem, was cat
gedruckt wurde, stammt aus cat
.
Oder Sie können etwas eingeben und Ctrl+ drücken d, um es ohne Zeilenumbruch zu senden cat
. Dann gibt es nach dem Eingegebenen und nach dem cat
Ausdrucken keinen Zeilenumbruch.
Ebenso cp -i
können Sie, wenn Sie dazu aufgefordert werden, interaktiv yCtrl+ dCtrl+ eingeben d(warum zweimal?Hier), cp
wird akzeptiert y
und Sie sehen y
eine Wiederholung durch die Zeilendisziplin, aber keinen Zeilenumbruch (weil Sie keinen eingegeben haben). cp
selbst druckt hier keinen Zeilenumbruch. Normalerweise (d. h. wenn Sie eingeben Enter) sieht das, was Sie sehen, aufgrund der Zeilendisziplin richtig aus (d. h. mit Zeilenumbrüchen an den richtigen Stellen). Wir können sagen, dass cp
eine Zeilendisziplin erwartet wird, die Zeilenumbruchzeichen an den geeigneten Stellen einfügt und so dafür sorgt, dass die Ausgabe gut aussieht.
Der Punkt istEs gibteine Zeilendisziplin zwischen Ihrer Tastatur und cp -i
. Es gibt wieder, was Sie eingeben, einschließlich einer neuen Zeile bei Enter.
In Ihrem yes | cp -i …
erhält cp
Eingaben fast so, als ob Sie yEnterüber eine Zeilendisziplin eingegeben hätten, aber dieses Mal gibt es nichts wie eine Zeilendisziplin, die das, was eingegeben wird, wiedergeben würde cp
. Aus diesem Grund haben Sie keine Zeilenumbrüche (und keine y
Zeichen) beobachtet.
Im Fall von wurden yes '' | cp -i …
die Zeilenumbrüche nach not overwritten
tatsächlich von gedruckt cp
. Was fehlt, ist ein Zeilenumbruch vor jedem not overwritten
. Ohne würden Sie in einer separaten Zeile sehen, yes
wenn Sie einfach Enterals Antwort auf die Eingabeaufforderung drücken würden.not overwritten
Auf dem Weg zur Lösung
Um das gewünschte Ergebnis zu erzielen, benötigen Sie etwas, das die Eingaben widerspiegelt, die in eingehen cp
. Auf den ersten Blick scheint es sich um eine echte Liniendisziplin zu handeln (hier ein paar Ideen:Wie man einen Befehl dazu bringt zu glauben, dass seine Ausgabe an ein Terminal geht; beachten Sie, dass wir nicht austricksen möchten cp
, sondern einen „Nebeneffekt“ des Vorhandenseins eines Terminals erzielen möchten) oder tee
zwischen yes
und cp
, wie folgt:
# both flawed
yes | socat STDIO EXEC:'cp -i …',pty
yes | tee >/dev/tty | cp -i …
Das Obige wird nicht gut funktionieren, da yes
die Ausgabe sofort und so weit wie möglich generiert wird. Es ist wie bei einem Benutzer, der hämmert, yEnteregal ob er dazu aufgefordert wird oder nicht. Wenn man dies wiederholt, sieht die Ausgabe viel schlechter aus als das, was Sie in der Frage gepostet haben.
Auch wenn Sie im Voraus wüssten, dass Sie nur ein benötigen yEnter, würde die Verwendung echo y
von anstelle von yes
nicht gut funktionieren, da die Eingabe höchstwahrscheinlich gesehen und gedruckt würde (durch die hinzugefügte Zeile „disciple“ oder durch tee
), bevor cp
die Eingabeaufforderung gedruckt wird.
Lösung
cp -i …
Eine gute Lösung besteht darin , mit zusätzlichem PTY zu arbeiten , aber nur dann Eingaben zu machen, wenn man dazu aufgefordert wird. expect(1)
kann das machen. Dies ist ein schnelles und einfaches expect
Skript:
#!/usr/bin/expect -f
set str [lindex $argv 0]
spawn -noecho cp -i {*}[lrange "$argv" 1 end]
while 1 {
expect {
"overwrite *\\?" { send "$str\r" }
eof exit
}
}
Benutzer mit lokalisierter Version cp
sollten das Muster anpassen "overwrite *\\?"
.
Beachten Sie, dass ich wenig Erfahrung mit habe expect
, das Skript ist möglicherweise nicht optimal oder sogar fehlerhaft. Betrachten Sie es als Proof of Concept. Speichern Sie das Skript als cpx
in einem Verzeichnis in Ihrem $PATH
, machen Sie es ausführbar ( chmod +x cpx
) und verwenden Sie es wie folgt:
cpx y ?.? smalls
# or
cpx n ?.? smalls
In der Praxis kann es sinnvoll sein, Shell-Aliase zu definieren:
alias cpy='cpx y'
alias cpn='cpx n'
und verwenden Sie sie wie folgt:
cpy ?.? smalls
# or
cpn ?.? smalls
Antwort2
Es gibt viele Möglichkeiten, den Alias zu umgehen und native zu verwenden cp
:
- Verwenden Sie den integrierten Befehl:
command cp
- Verwenden Sie den vollständigen Pfad des Befehls:
/bin/cp
- Fügen Sie an beliebiger Stelle im Befehlsnamen ein \ hinzu, zum Beispiel:
\cp
- Zitieren Sie den Befehl:
"cp"
oder'cp'
Antwort3
Sie können vor Ihrem Code „yes |“ verwenden.
yes | cp -i ?.? smalls