Wie kann ich mit xargs kopieren von Dateien, die Leerzeichen und Anführungszeichen in Ihrem Namen?
Ich versuche, kopieren Sie eine Reihe von Dateien unter einem Verzeichnis eine Reihe von Dateien mit Leerzeichen und einfache Anführungszeichen in Ihrem Namen. Wenn ich versuche zu string zusammen find
und grep
mit xargs
, bekomme ich die folgende Fehlermeldung:
find .|grep "FooBar"|xargs -I{} cp "{}" ~/foo/bar
xargs: unterminated quote
Irgendwelche Vorschläge für eine stabilere Verwendung von xargs?
Dies ist auf Mac OS X 10.5.3 (Leopard) mit BSD xargs
.
- Die GNU-xargs Fehlermeldung für diese mit einem Dateinamen mit einem Apostroph ist eher hilfreich: "xargs: unerreicht einfache Anführungszeichen; standardmäßig Zitate sind spezielle, xargs, es sei denn, Sie verwenden die option -0".
- GNU-xargs hat auch
--delimiter
option (-d
). Versuchen Sie es mit\n
als Trennzeichen, Dies verhindert, dassxargs
von der Trennung von Zeilen mit Leerzeichen in mehrere Worte/Argumente.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Kombinieren Sie all das in einem einzigen
find
Befehl:Dieser Griff Dateinamen und Verzeichnisse mit Leerzeichen in Ihnen. Sie können
-name
zu bekommen groß-und Kleinschreibung Ergebnisse.Hinweis: Die
--
flag übergebencp
verhindert, dass es bei der Verarbeitung von Dateien, beginnend mit-
als Optionen.find .. -exec cp -t ~/foo/bar -- {} +
xargs
ist nicht erforderlich, um das Problem, das Sie beschreiben,find
schon unterstützt mit der-exec
+
Satzzeichen.foobar
ist die Ausgabe von einigen anderen Befehl, wie kann ich dies durchführen ? Ich danke Ihnen sehrfoobar
mit entweder$(your-command args)
oder`your-command args`
.{}
innerhalb von Anführungszeichen schützt die Leerzeichen im Dateinamen/Pfad. Ist es das, was Sie sich beziehen?xargs
mit Leerzeichen.find . -print0 | grep --null 'FooBar' | xargs -0 ...
Weiß ich nicht, ob
grep
unterstützt--null
noch, obxargs
unterstützt-0
auf Leopard, aber unter GNU es ist alles gut.grep -{z|Z}
bedeutet "sich Verhalten, als zgrep" (Dekomprimieren) und nicht die beabsichtigte "drucken Sie eine null-byte nach jedem Dateinamen ein". Verwendengrep --null
zur Erreichung der letzteren.find . -name 'FooBar' -print0 | xargs -0 ...
?-name
oder-path
gut funktionieren. Der OP hat angegeben, den Einsatz vongrep
, vermutlich, weil Sie möchten, filtern Sie die Liste mithilfe von regulären Ausdrücken.Binary file (standard input) matches
von grep, wenn Sie dies versuchen, weil-print0
; verwendengrep -a
zu zwingen, es zu interpretieren, das Rohr.duperemove
— die übergabe einer 0-endete mit dem Namen Ergebnisse inNo such file or directory
.xargs -d '\n'
, sonst xargs brechen würde-Dateien zu Räumen. Versuchen Sie dies:touch "foo bar"; echo -e "foo bar" | xargs -0 ls
, Sie würden eine Fehlermeldung erhalten. Aber das ersetzen der-0
mit-d '\n'
funktioniert. Siehe auch diese Antwort.xargs -0
in Verbindung mitfind -print0
. Letztere druckt Dateinamen mit einem NUL-terminator und ehemalige empfängt Dateien auf diese Weise. Warum? Dateinamen in Unix enthalten kann, die neue-Zeile-Zeichen. Aber Sie können nicht NUL-Zeichen.Der einfachste Weg, das zu tun, was das ursprüngliche Plakat will ist, ändern Sie das Trennzeichen aus alle whitespace-Zeichen nur auf die end-of-line-Zeichen wie diese:
sed -e 's_\(.*\)_"\1"_g'
zu zwingen, Anführungszeichen um den Namen der Dateixargs
.xargs: illegal option -- d
B
undC
existieren in einer großen Verzeichnis. Ein Benutzer erstellt eine neue Datei mit dem NamenB\nC
. Später, dass der Benutzer geht Weg und jemand reinigt, dass alle Dateien des Benutzers durch Abfragen der Eigentümer und Rohrleitungen eine Liste Ihrer Dateien durchxargs -d "\n" rm
. DateienB
undC
werden umgehend gelöscht.)Dies ist effizienter, als es nicht laufen "cp" mehrfach:
Ich lief in das gleiche problem. Hier ist, wie ich es gelöst:
Ich verwendet
sed
zu ersetzen jede Zeile mit der gleichen Zeile, aber umgeben von doppelten Anführungszeichen. Aus dersed
Mann-Seite, "...Ein kaufmännisches und-Zeichen (`&"), die in der Ersatz ist ersetzt durch den string passend zu den RE..." -- in diesem Fall.*
, wird die gesamte Zeile.Löst dies das
xargs: unterminated quote
Fehler.sed s/.*/\"&\"/
um es an die Arbeit."
im - es sei denn sed auch Zitate Zitate?sed
ist genial und für die richtige Lösung ohne das umschreiben der problem!Diese Methode funktioniert auf Mac OS X v10.7.5 (Lion):
Ich auch getestet, die genaue syntax, die Sie geschrieben. Dass das auch geklappt, auf 10.7.5.
-I
impliziert-L 1
(so sagt es das Handbuch), was bedeutet, dass der cp-Befehl ausgeführt wird einmal pro Datei = v langsam.find ... -print0
undxargs -0
zu arbeiten, um xargs ' s "standardmäßig Zitate sind spezielle". Zweitens, verwenden in der Regel'{}'
nicht{}
Befehle übergeben xargs, zum Schutz gegen Leerzeichen und Sonderzeichen.Einfach nicht mit
xargs
. Es ist ein nettes Programm aber es geht nicht gut mitfind
wenn konfrontiert mit nicht trivialen Fällen.Hier ist ein portables (POSIX) - Lösung, d.h. eine, die nicht erfordern
find
,xargs
odercp
GNU-spezifische Erweiterungen:Beachten Sie das Ende
+
statt der üblichen;
.Diese Lösung:
richtig verarbeitet Dateien und Verzeichnisse mit Leerzeichen, Zeilenumbrüche oder was auch immer exotische Zeichen.
funktioniert auf jedem Unix-und Linux-system, selbst diejenigen nicht, die das GNU toolkit.
nicht
xargs
ist ein nettes und nützliches Programm, erfordert aber auch viel Trickserei und nicht-standard-features, um richtig zu behandelnfind
Ausgabe.ist auch effizienter (Lesen schneller) als die akzeptierten und die meisten, wenn nicht alle anderen Antworten.
Beachten Sie auch, dass trotz allem, was ist anders in einigen anderen Antworten oder Kommentare zitieren
{}
ist nutzlos (es sei denn, Sie sind mit den exotischenfish
shell).find
tun können, wasxargs
nicht ohne Aufwand.Blick in die --null-commandline-option für xargs mit -print0-option in der zu finden.
Für diejenigen, die stützt sich auf Befehle, andere als finden, z.B.
ls
:-I
impliziert-L 1
Ich glaube, dass diese Arbeit zuverlässig für ein beliebiges Zeichen außer Zeilenvorschub (und ich vermute, dass, wenn Sie haben die line-feeds in Ihren Dateinamen, dann hast du schlimmere Probleme als diese). Es erfordert keine GNU findutils, nur Perl -, so ist es sollte ziemlich viel überall.
mkdir test && cd test && perl -e 'open $fh, ">", "this-file-contains-a-\n-here"' && ls | od -tx1
|perl -lne 'print quotemeta'
ist genau das, was ich gesucht habe. Andere Beiträge hier nicht helfen mir da lieber alsfind
ich brauchte, umgrep -rl
zu gewaltig reduzieren Sie die Anzahl der PHP-Dateien nur die malware-infizierten.Habe ich herausgefunden, dass folgende syntax funktioniert gut für mich.
In diesem Beispiel, ich bin auf der Suche nach den größten 200 Dateien über 1.000.000 bytes, die in das filesystem gemountet unter "/usr/pcapps".
Perl-line-liner zwischen "finden" und "xargs" entweicht/quotes jeden Rohling so "xargs" geht irgendwelche Dateinamen mit Leerzeichen zu "ls" als ein einziges argument.
Sich bewusst sein, dass die meisten Optionen diskutiert, die in anderen Antworten sind nicht standard auf Plattformen, die nicht mit den GNU-utilities (Solaris, AIX, HP-UX, zum Beispiel). Finden Sie die POSIX Spezifikation für "standard" xargs Verhalten.
Finde ich auch das Verhalten von xargs wobei er führt den Befehl mindestens einmal, auch ohne Eingabe, um ein ärgernis sein.
Schrieb ich meine eigene private version von xargs (xargl), um sich mit den Problemen von Leerzeichen bei Namen (nur Zeilenumbrüche trennen - obwohl die "find ... -print0' und 'xargs -0' Kombination ist Recht ordentlich, da dürfen im Dateinamen nicht enthalten ASCII-NUL '\0' - Zeichen. Meine xargl ist nicht so abgeschlossen, wie es hätte sein müssen, lohnt sich die Veröffentlichung - vor allem, da GNU Ausstattung, sind mindestens genauso gut.
find
muss nichtxargs
an Erster Stelle (und das gilt schon 11 Jahre her).Mit der Bash (nicht POSIX) Sie können mit dem Prozess der substitution, um die aktuelle Zeile innerhalb einer Variablen. Dies ermöglicht die Verwendung der Anführungszeichen escape-Sonderzeichen:
Für mich, ich war versucht, etwas zu tun ein wenig anders. Wollte ich kopieren meine .txt-Dateien in meinem tmp-Ordner. Die .txt-Dateinamen enthalten Leerzeichen und Apostroph-Zeichen. Dies funktionierte auf meinem Mac.
Wenn finden und xarg-Versionen auf Ihrem system nicht unterstützt
-print0
und-0
- switches (zum Beispiel AIX find und xargs) Sie können mit diesem schrecklich aussehenden code:Hier sed wird kümmern sich um die Flucht der Räume und Angebote für xargs.
Getestet auf AIX 5.3
Erstellte ich eine kleine portable wrapper-Skript namens "xargsL" rund "xargs", das behebt die meisten der Probleme.
Im Gegensatz zu xargs, xargsL akzeptiert einen Pfadnamen pro Zeile. Die Pfadnamen können beliebige Zeichen enthalten, außer (natürlich), newline oder NUL-bytes.
Wird keine Quotierung erlaubt oder unterstützt Sie in der Dateiliste - Dateinamen enthalten können alle Arten von Leerzeichen, umgekehrte Schrägstriche, backticks, der shell-wildcard-Zeichen und die wie - xargsL verarbeiten Sie als literal-Zeichen, no harm done.
Als zusätzlichen bonus feature, xargsL wird nicht den Befehl einmal ausgeführt, wenn es keine Eingabe!
Beachten Sie den Unterschied:
Alle Argumente gegeben xargsL weitergereicht wird an xargs.
Hier ist die "xargsL" POSIX-shell-Skript:
Legen Sie das Skript in einem Verzeichnis in seinem $PATH und vergessen Sie nicht,
$ chmod +x xargsL
das Skript dort machen Sie es ausführbar.
bill_starr Perl-version nicht gut für eingebettete Zeilenumbrüche (nur meistert mit Leerzeichen). Für diejenigen, die auf z.B. Solaris, wo man nicht die GNU-tools, eine komplette version sein könnte (mit sed)...
passen Sie die find-und grep-Argumente oder andere Befehle, die Sie benötigen, aber die sed wird fix your eingebettete Zeilenumbrüche/Leerzeichen/tabs.
Ich verwendet Bill Star ' s Antwort leicht modifiziert auf Solaris:
Dies wird setzen Sie Anführungszeichen um jede Zeile. Ich habe nicht die '-l' option, obwohl es vermutlich helfen würde.
Die Datei-Liste ich wollte aber vielleicht haben '-', aber keine Zeilenumbrüche. Ich habe nicht verwendet die Ausgabe-Datei mit anderen Befehlen, wie ich will, zu überprüfen, was gefunden wurde, bevor ich beginne einfach Massiv löschen Sie via xargs.
Spielte ich mit diesem ein wenig, begann der Betrachtung geändert wird, xargs, und festgestellt, dass für die Art der Nutzung, falls wir hier reden, eine einfache Reimplementierung in Python ist eine bessere Idee.
Für eine Sache, mit ~80 Zeilen code für das ganze bedeutet, es ist einfach, um herauszufinden, was Los ist, und wenn anderes Verhalten erforderlich ist, können Sie einfach es zu hacken in ein neues Skript in weniger Zeit als es dauert, eine Antwort zu bekommen auf irgendwo wie Stack Overflow.
Sehen https://github.com/johnallsup/jda-misc-scripts/blob/master/yargs und https://github.com/johnallsup/jda-misc-scripts/blob/master/zargs.py.
Mit yargs wie geschrieben (und Python 3 installiert) können Sie eingeben:
tun das kopieren 203-Dateien zu einem Zeitpunkt. (Hier 203 ist nur ein Platzhalter, natürlich, und mit einer seltsamen Nummer wie die 203 macht es klar, dass diese Nummer hat keine andere Bedeutung.)
Wenn Sie wirklich wollen, etwas schneller und ohne die Notwendigkeit für Python, nehmen zargs und yargs als Prototypen und schreiben Sie in C++ oder C.
Müssen Sie möglicherweise grep Foobar-Verzeichnis wie:
-i
ist veraltet, und-I
sollte stattdessen verwendet werden.Frame Herausforderung — Fragen Sie wie zu verwenden xargs. Die Antwort ist: Sie nicht verwenden, xargs, weil Sie es nicht brauchen.
Den Kommentar von
user80168
beschreibt eine Möglichkeit, dies direkt mit cp, ohne daß die cp für jede Datei:Dies funktioniert, weil:
cp -t
flag ermöglicht die Ziel-directory in der Nähe der Anfangcp
, anstatt in der Nähe des Ende. Vonman cp
:Den
--
flag erzähltcp
zu interpretieren alles nach wie eine mit dem Namen, keine Flagge, so dass die Dateien beginnend mit-
oder--
nicht zu verwechselncp
; Sie müssen noch dies, weil die-
/--
Zeichen werden interpretiert, indemcp
, während andere spezielle Zeichen werden von der shell interpretiert.Den
find -exec command {} +
Variante tut im wesentlichen das gleiche wie xargs. Vonman find
:Durch die Nutzung dieser bei findest direkt, das vermeidet die Notwendigkeit, ein Rohr oder ein shell-Aufruf, so dass Sie nicht brauchen, um über alle bösen Zeichen in Dateinamen.
Wenn Sie die Bash benutzen, können Sie konvertieren stdout zu einem array von Zeilen, die von
mapfile
:Die Vorteile sind:
Können Sie Anhängen, mit anderen Argumenten auf den Dateinamen. Für
cp
können Sie auch:jedoch einige Befehle, die nicht über eine solche Funktion.
Nachteile:
Gut... wer weiß, ob die Bash ist auf OS X?
|grep
wird nicht funktionieren