Ich habe ungefähr 10 php.ini
Dateien auf meinem System, die sich überall befinden, und ich wollte sie schnell durchsuchen. Ich habe diesen Befehl ausprobiert:
locate php.ini | xargs vi
Aber vi
warnt mich Input is not from a terminal
und dann wird die Konsole wirklich komisch - danach muss ich drücken, um :q!
zu beenden vi
und dann die Verbindung zur SSH-Sitzung zu trennen und die Verbindung wiederherzustellen, damit sich die Konsole wieder normal verhält.
Ich denke, ich verstehe irgendwie, was hier passiert - im Grunde ist der Befehl beim vi
Starten noch nicht beendet, so dass der Befehl möglicherweise noch nicht beendet ist und vi
nicht glaubt, dass sich das Terminal im normalen Modus befindet.
Ich habe keine Ahnung, wie ich das beheben soll. Ich habe Google und auch unix.stackexchange.com mit Pech durchsucht.
reset
, um Ihr Terminal zurückzusetzen, wenn es vermasselt wird (Sie müssen die Verbindung nicht von der SSH-Sitzung trennen).Antworten:
Hinweis: Dies tritt auf, wenn Ihre Dateipfade Leerzeichen enthalten, entspricht jedoch funktional Ihrem Befehl.
Diese nächste Version behandelt Leerzeichen ordnungsgemäß, ist jedoch etwas komplizierter (Zeilenumbrüche in Dateinamen werden sie jedoch weiterhin beschädigen).
Erläuterung:
Was passiert ist, dass Programme ihre Dateideskriptoren von dem Prozess erben, der sie erzeugt hat.
xargs
hat seinen STDIN mit dem STDOUT von verbundenlocate
,vi
hat also keine Ahnung, in was der ursprüngliche STDIN wirklich steckt.quelle
xargs
, was nicht direkt mit der Shell (oderfind
) gemacht werden konnte. Ich kann mir jedoch Fälle vorstellen, in denen dies die beste Lösung wäre. Also, solange Sie verstehen, wasxargs
tut, wie es die Argumente aufteilt, wie es das Programm ausführt usw. und es richtig verwendet, würde ich sagen, machen Sie es :-P... | awk '{print $3}' | xargs | sed -e 's/ /+/g' | bc
(um alle Werte von Feld 3 zu addieren). oder mitsed -e 's/ /|/g'
, um einen regulären Ausdruck zu erstellen. und ja, wie bei jedem Tool müssen Sie wissen, wie man es verwendet und welche Einschränkungen und Einschränkungen es hat.vi $(...)
Ansatz hat auch ein Problem mit Platzhaltern in anderen Shells alszsh
.xargs
Ansatz neben dem Leerzeichen-Problem auch Dateinamen mit einfachen Anführungszeichen, doppelten Anführungszeichen und umgekehrten Schrägstrichen ein Problem darstellen.Diese Frage wurde bereits im Super User- Forum gestellt.
Zitat aus der Antwort von @ grawity auf diese Frage:
Dies wird in den Handbuchseiten für xarg erwähnt. Von OSX / BSD:
Daher können Sie unter OSX den folgenden Befehl verwenden:
Während es in der GNU-Version keinen direkten Schalter gibt, funktioniert dieser Befehl. (Stellen Sie sicher, dass Sie die
dummy
Zeichenfolge einschließen , da sonst die erste Datei gelöscht wird.)Die oben genannten Lösungen wurden von Jaime McGuigan von SuperUser zur Verfügung gestellt . Fügen Sie sie hier für zukünftige Besucher hinzu, die die Site nach diesem Fehler durchsuchen.
quelle
xargs sh -c 'emacs "$@" < /dev/tty' emacs
eine flexiblere und tragbarere Alternative (obwohl es für GNU irgendwie lustig ist, die Portabilität den Funktionen vorzuziehen :).Mit GNU
findutils
und einer Shell mit Unterstützung für die Prozessersetzung (ksh, zsh, bash) können Sie Folgendes tun:Die Idee ist, die Dateiliste
-a filename
eher über ein als über ein stdin zu übergeben. Die Verwendung-0
stellt sicher, dass es funktioniert, unabhängig davon, welche Zeichen oder Nichtzeichen die Dateinamen enthalten können.Mit
zsh
könnten Sie tun:(Wo
0
ist das Parametererweiterungsflag, das auf NULs aufgeteilt werden soll).Beachten Sie jedoch, dass im Gegensatz dazu
xargs -r
immer nochvi
ohne Argument ausgeführt wird, wenn keine Datei gefunden wird.quelle
Mehrere php.ini im selben Editor bearbeiten?
Versuchen:
vim -o $(locate php.ini)
quelle
Dieser Fehler tritt auf, wenn vim aufgerufen wird und anstelle des Terminals mit dem Ausgang der vorherigen Pipeline verbunden ist und andere unerwartete Eingaben (wie NULs) empfängt. Das gleiche passiert , wenn Sie laufen:
vim < /dev/null
, soreset
Befehl in diesem Fall hilft. Dies wird gut durch die Gravität bei Superuser erklärt .Unter Unix / OSX können Sie verwenden ,
xargs
mit-o
Parametern, wie zB:Versuchen Sie unter Linux die folgende Problemumgehung:
Verwenden Sie alternativ GNU , um die Zuweisung
parallel
vonxargs
tty zu erzwingen. Beispiel:Hinweis: Unter
parallel
Unix / OSX funktioniert es nicht, da es unterschiedliche Parameter hat und tty nicht unterstützt.Viele andere beliebte Befehle bieten ebenfalls eine Pseudo-Tty-Zuweisung (wie
-t
inssh
). Suchen Sie daher nach Hilfe.Alternativ können Sie
find
Dateinamen zum Bearbeiten übergeben. Sie müssen sie also nicht verwenden.xargs
Verwenden Sie einfach Folgendes-exec
:quelle
@ Patricks
IFS
Hack ist nur für dumme Muscheln wiebash
und notwendigzsh
.fish
teilt die Zeichenfolge standardmäßig in Zeilenumbrüche.Und Gott helfe uns allen, wenn einer von uns tatsächlich eine Datei mit einem Zeilenumbruch im Namen hat. Nach 17 Jahren mit Linux habe ich es noch kein einziges Mal gesehen. Ich würde mich nur darum kümmern, Dateinamen mit Zeilenumbrüchen für Skripte zu unterstützen, die auf jeden Fall funktionieren müssen, aber solche Skripte werden wahrscheinlich nicht interaktiv ausgeführt.
quelle
zsh
wird standardmäßig auf SPC, TAB, NL und NUL aufgeteilt. Im Vergleich dazubash
wird das Ergebnis nicht globalisiert, sodass Platzhalterzeichen in Dateinamen kein Problem darstellen. In würdenzsh
Sie tunIFS=$'\0'; vi $(locate -0 php.ini)
oder wie ich in meiner Antwortvi ${(0)"$(locate -0 php.ini)"}
für einen expliziten Aufteilungsoperator gezeigt habe. Beachten Sie auch tcsh'svi "`locate php.ini`"
$ f='not there'<ret>$ ls $f<ret>
aber das funktioniert nicht: lsecho not there
. OK sieht so aus, als müsste ich das ein bisschen aktualisieren.ls "$(echo test; echo other test)"
. Nur Fisch macht das Richtige.$IFS
oder über explizite Operatoren (f
und0
Parametererweiterungsflags) zu teilen . Bei beliebigen Dateinamen ist das Aufteilen nach Wörtern oder nach Zeilen gleichermaßen falsch . Sie müssen auf NUL aufteilen oder eine Codierung analysieren, wasfish
nicht möglich ist. Inzsh
, das istIFS=$'\0'; ls -ld -- $(printf '%s\0' "$file1" "$file2")
oderls -ld -- ${(0)"$(printf '%s\0' "$file1" "$file2")"}
Ein schneller Weg , es zu tun, vorausgesetzt , Sie keine der Dateipfade garantieren können , enthalten SPC, TAB, NL,
*
,?
,[
Zeichen (auch\
und{...}
in einigen Muscheln) ist zurück-Zecken zu verwenden (auch bekannt als Grab Akzente) , einen Befehl auszuführen vor Ein weiterer Befehl wird ausgeführt.Z.B
Der in den Back-Ticks enthaltene Befehl wird zuerst ausgeführt. Die Ausgabe des enthaltenen Befehls wird dann durch den vor den Back-Ticks angegebenen Befehl ausgeführt.
In der obigen Zeile wird der
find / -type f -name 'php.ini'
Befehl beispielsweise zuerst ausgeführt, die Ausgabevi
gesendet und dann für das Ergebnis von split + glob ausgeführt, das auf diese Ausgabe angewendet wird.quelle
$(find ...)
stattdessen.vi
mit dieser Methode . Es ist durchaus möglich, dass neue Zeilen oder Leerzeichen unterbrochen werden, je nachdem, wievi
die Ausgabe gelesen und ausgeführt wird.