Ich versuche, eine Reihe von Dateien unter ein Verzeichnis zu kopieren, und einige Dateien enthalten Leerzeichen und einfache Anführungszeichen. Wenn ich versuche, zusammen find
und grep
mit zu fädeln xargs
, erhalte ich die folgende Fehlermeldung:
find .|grep "FooBar"|xargs -I{} cp "{}" ~/foo/bar
xargs: unterminated quote
Irgendwelche Vorschläge für eine robustere Verwendung von xargs?
Dies ist unter Mac OS X 10.5.3 (Leopard) mit BSD xargs
.
--delimiter
option (-d
). Versuchen Sie es mit\n
als Trennzeichen. Dies verhindert, dassxargs
Zeilen mit Leerzeichen in mehrere Wörter / Argumente getrennt werden.Antworten:
Sie können all das in einem einzigen
find
Befehl kombinieren :Dadurch werden Dateinamen und Verzeichnisse mit Leerzeichen behandelt. Sie können verwenden
-name
, um zwischen Groß- und Kleinschreibung unterscheidende Ergebnisse zu erhalten.Hinweis: Das übergebene
--
Flagcp
verhindert , dass Dateien verarbeitet werden, die-
als Optionen beginnen.quelle
xargs
ist jedoch nicht erforderlich, um das von Ihnen beschriebene Problem zu beheben. Erfind
unterstützt ihn bereits mit der-exec
+
Interpunktion.find . -print0 | grep --null 'FooBar' | xargs -0 ...
Ich weiß nicht, ob Leopard
grep
unterstützt--null
oderxargs
unterstützt-0
, aber bei GNU ist alles gut.quelle
grep -{z|Z}
bedeutet "Verhalten als zgrep" (Dekomprimieren) und nicht das beabsichtigte "Drucken eines Null-Bytes nach jedem Dateinamen". Verwenden Siegrep --null
, um Letzteres zu erreichen.find . -name 'FooBar' -print0 | xargs -0 ...
?-name
oder gut-path
funktionieren. Das OP hat die Verwendung von angegebengrep
, vermutlich weil sie die Liste mit regulären Ausdrücken filtern möchten.xargs -0
in Verbindung mitfind -print0
. Letzterer druckt Dateinamen mit einem NUL-Terminator und Ersterer empfängt Dateien auf diese Weise. Warum? Dateinamen in Unix können Zeilenumbrüche enthalten. Sie dürfen jedoch keine NUL-Zeichen enthalten.Der einfachste Weg, um das zu tun, was das Originalplakat will, besteht darin, das Trennzeichen von einem Leerzeichen in ein Zeilenendezeichen wie das folgende zu ändern:
quelle
sed -e 's_\(.*\)_"\1"_g'
an Kraft Anführungszeichen um den Dateinamenxargs
.xargs: illegal option -- d
Dies ist effizienter, da "cp" nicht mehrmals ausgeführt wird:
quelle
Ich bin auf das gleiche Problem gestoßen. So habe ich es gelöst:
Früher habe ich
sed
jede Eingabezeile durch dieselbe Zeile ersetzt, aber von doppelten Anführungszeichen umgeben. Auf dersed
Manpage wird " ... Ein kaufmännisches Und (" & "), das in der Ersetzung erscheint, durch die Zeichenfolge ersetzt, die mit der RE übereinstimmt ... " - in diesem Fall.*
die gesamte Zeile.Dies löst den
xargs: unterminated quote
Fehler.quelle
sed s/.*/\"&\"/
, damit es funktioniert."
in behandeln - es sei denn, sed zitiert auch Anführungszeichen?sed
ist genial und vorerst die richtige Lösung, ohne das Problem neu zu schreiben!Diese Methode funktioniert unter Mac OS X 10.7.5 (Lion):
Ich habe auch die genaue Syntax getestet, die Sie veröffentlicht haben. Das hat auch am 10.7.5 gut funktioniert.
quelle
-I
impliziert aber-L 1
(so heißt es im Handbuch), was bedeutet, dass der Befehl cp einmal pro Datei = v langsam ausgeführt wird.find ... -print0
undxargs -0
arbeiten, um "standardmäßig sind Anführungszeichen etwas Besonderes" zu verwenden. Zweitens: Verwenden Sie'{}'
diese{}
Option im Allgemeinen nicht in Befehlen, die an xargs übergeben werden, um sie vor Leerzeichen und Sonderzeichen zu schützen.Nur nicht benutzen
xargs
. Es ist ein ordentliches Programm, aber es passt nicht gutfind
zu nicht trivialen Fällen.Hier ist eine tragbare (POSIX) Lösung, dh eine, die keine benötigt
find
,xargs
odercp
GNU-spezifische Erweiterungen:Beachten Sie das Ende
+
anstelle des üblicheren;
.Diese Lösung:
Behandelt Dateien und Verzeichnisse mit eingebetteten Leerzeichen, Zeilenumbrüchen oder anderen exotischen Zeichen korrekt.
funktioniert auf jedem Unix- und Linux-System, auch auf solchen, die das GNU-Toolkit nicht bereitstellen.
verwendet kein
xargs
schönes und nützliches Programm, erfordert jedoch zu viele Optimierungen und nicht standardmäßige Funktionen, um diefind
Ausgabe richtig zu handhaben .ist auch effizienter ( schneller lesen ) als die akzeptierten und die meisten, wenn nicht alle anderen Antworten.
Beachten Sie auch, dass das Zitieren trotz der Angaben in einigen anderen Antworten oder Kommentaren
{}
nutzlos ist (es sei denn, Sie verwenden die exotischefish
Shell).quelle
find
kann tun, wasxargs
ohne Overhead geht.Verwenden Sie die Befehlszeilenoption --null für xargs mit der Option -print0 in find.
quelle
Für diejenigen, die sich auf andere Befehle als find verlassen, z
ls
.quelle
-I
impliziert-L 1
Ich glaube, dass dies für jeden Charakter außer Zeilenvorschub zuverlässig funktioniert (und ich vermute, dass Sie schlimmere Probleme haben, wenn Sie Zeilenvorschübe in Ihren Dateinamen haben). Es erfordert keine GNU-Findutils, nur Perl, also sollte es so ziemlich überall funktionieren.
quelle
mkdir test && cd test && perl -e 'open $fh, ">", "this-file-contains-a-\n-here"' && ls | od -tx1
|perl -lne 'print quotemeta'
ist genau das, wonach ich gesucht habe. Andere Beiträge hier haben mir nicht geholfen, dafind
ichgrep -rl
die Anzahl der PHP-Dateien nicht nur auf mit Malware infizierte Dateien reduzieren musste, sondern auch.Ich habe festgestellt, dass die folgende Syntax für mich gut funktioniert.
In diesem Beispiel suche ich nach den 200 größten Dateien über 1.000.000 Bytes im Dateisystem, das unter "/ usr / pcapps" bereitgestellt wird.
Der Perl-Zeilenumbruch zwischen "find" und "xargs" maskiert / zitiert jedes Leerzeichen, sodass "xargs" einen beliebigen Dateinamen mit eingebetteten Leerzeichen als einzelnes Argument an "ls" übergibt.
quelle
Frame Challenge - Sie fragen, wie Sie Xargs verwenden. Die Antwort lautet: Sie verwenden keine Xargs, weil Sie sie nicht benötigen.
Der Kommentar von
user80168
beschreibt eine Möglichkeit, dies direkt mit cp zu tun, ohne cp für jede Datei aufzurufen:Dies funktioniert, weil:
cp -t
Flag kann das Zielverzeichniscp
eher am Anfang als am Ende angegeben werden. Vonman cp
:Das
--
Flag weist darauf hincp
, dass alles danach als Dateiname und nicht als Flag interpretiert werden soll, sodass Dateien mit beginnen-
oder--
nicht verwechselncp
. Sie benötigen dies weiterhin, da die-
/--
-Zeichen von interpretiert werdencp
, während alle anderen Sonderzeichen von der Shell interpretiert werden.Die
find -exec command {} +
Variante macht im Wesentlichen dasselbe wie xargs. Vonman find
:Wenn Sie dies direkt in find verwenden, wird die Notwendigkeit eines Pipe- oder Shell-Aufrufs vermieden, sodass Sie sich keine Gedanken über böse Zeichen in Dateinamen machen müssen.
quelle
Beachten Sie, dass die meisten der in anderen Antworten beschriebenen Optionen auf Plattformen, auf denen die GNU-Dienstprogramme nicht verwendet werden (z. B. Solaris, AIX, HP-UX), nicht Standard sind. Informationen zum Standardverhalten von xargs finden Sie in der POSIX- Spezifikation.
Ich finde auch das Verhalten von xargs, bei dem der Befehl mindestens einmal ausgeführt wird, auch ohne Eingabe, ein Ärgernis.
Ich habe meine eigene private Version von xargs (xargl) geschrieben, um die Probleme von Leerzeichen in Namen zu lösen (nur Zeilenumbrüche sind getrennt - obwohl die Kombination 'find ... -print0' und 'xargs -0' ziemlich ordentlich ist, da Dateinamen dies nicht können enthalten ASCII NUL '\ 0' Zeichen. Mein xargl ist nicht so vollständig, wie es sein müsste, um veröffentlicht zu werden - zumal GNU über mindestens ebenso gute Funktionen verfügt.
quelle
find
braucht das überhaupt nichtxargs
(und das war schon vor 11 Jahren so).Mit Bash (nicht POSIX) können Sie die Prozessersetzung verwenden, um die aktuelle Zeile innerhalb einer Variablen abzurufen. Auf diese Weise können Sie Anführungszeichen verwenden, um Sonderzeichen zu umgehen:
quelle
Für mich habe ich versucht, etwas anderes zu machen. Ich wollte meine TXT-Dateien in meinen tmp-Ordner kopieren. Die .txt-Dateinamen enthalten Leerzeichen und Apostrophzeichen. Dies funktionierte auf meinem Mac.
quelle
Wenn find- und xarg-Versionen auf Ihrem System nicht unterstützt
-print0
und-0
wechselt (z. B. AIX find und xargs), können Sie diesen schrecklich aussehenden Code verwenden:Hier kümmert sich sed darum, den Leerzeichen und Anführungszeichen für xargs zu entkommen.
Getestet unter AIX 5.3
quelle
Ich habe ein kleines tragbares Wrapper-Skript namens "xargsL" um "xargs" erstellt, das die meisten Probleme behebt.
Im Gegensatz zu xargs akzeptiert xargsL einen Pfadnamen pro Zeile. Die Pfadnamen können beliebige Zeichen außer (offensichtlich) Zeilenumbrüchen oder NUL-Bytes enthalten.
In der Dateiliste ist kein Anführungszeichen zulässig oder wird nicht unterstützt. Ihre Dateinamen können alle Arten von Leerzeichen, Backslashes, Backticks, Shell-Platzhalterzeichen und dergleichen enthalten. XargsL verarbeitet sie als Literalzeichen, ohne dass Schaden entsteht.
Als zusätzlichen Bonus - Feature wird xargsL nicht den Befehl ausführen einmal , wenn es keine Eingabe!
Beachten Sie den Unterschied:
Alle Argumente, die xargsL gegeben werden, werden an xargs weitergeleitet.
Hier ist das POSIX-Shell-Skript "xargsL":
Legen Sie das Skript in einem Verzeichnis in Ihrem $ PATH ab und vergessen Sie es nicht
$ chmod +x xargsL
das Skript dort, um es ausführbar zu machen.
quelle
Die Perl-Version von bill_starr funktioniert nicht gut für eingebettete Zeilenumbrüche (nur für Leerzeichen). Für diejenigen unter zB Solaris, bei denen Sie nicht über die GNU-Tools verfügen, ist möglicherweise eine vollständigere Version (mit sed) ...
Passen Sie die Argumente find und grep oder andere Befehle nach Bedarf an, aber das sed korrigiert Ihre eingebetteten Zeilenumbrüche / Leerzeichen / Tabulatoren.
quelle
Ich habe die Antwort von Bill Star verwendet, die unter Solaris leicht modifiziert wurde:
Dadurch werden Anführungszeichen um jede Zeile gesetzt. Ich habe die Option '-l' nicht verwendet, obwohl sie wahrscheinlich helfen würde.
Die Dateiliste, in die ich gegangen bin, hat möglicherweise '-', aber keine Zeilenumbrüche. Ich habe die Ausgabedatei nicht mit anderen Befehlen verwendet, da ich überprüfen möchte, was gefunden wurde, bevor ich anfange, sie über xargs massiv zu löschen.
quelle
Ich habe ein wenig damit gespielt, angefangen, über das Ändern von xargs nachzudenken, und festgestellt, dass für den Anwendungsfall, über den wir hier sprechen, eine einfache Neuimplementierung in Python eine bessere Idee ist.
Zum einen bedeutet ~ 80 Codezeilen für das Ganze, dass es einfach ist, herauszufinden, was vor sich geht, und wenn ein anderes Verhalten erforderlich ist, können Sie es einfach in kürzerer Zeit als nötig in ein neues Skript hacken eine Antwort auf irgendwo wie Stack Overflow.
Siehe https://github.com/johnallsup/jda-misc-scripts/blob/master/yargs und https://github.com/johnallsup/jda-misc-scripts/blob/master/zargs.py .
Wenn yargs wie geschrieben (und Python 3 installiert) ist, können Sie Folgendes eingeben:
um jeweils 203 Dateien zu kopieren. (Hier ist 203 natürlich nur ein Platzhalter, und die Verwendung einer seltsamen Zahl wie 203 macht deutlich, dass diese Zahl keine andere Bedeutung hat.)
Wenn Sie wirklich etwas schneller und ohne Python benötigen, nehmen Sie Zargs und Yargs als Prototypen und schreiben Sie sie in C ++ oder C neu.
quelle
Möglicherweise müssen Sie das Foobar-Verzeichnis wie folgt durchsuchen:
quelle
-i
ist es veraltet und-I
sollte stattdessen verwendet werden.Wenn Sie Bash verwenden, können Sie stdout in ein Array von Zeilen konvertieren , indem Sie
mapfile
:Die Vorteile sind:
Sie können andere Argumente an die Dateinamen anhängen. Denn
cp
Sie können auch:Einige Befehle verfügen jedoch nicht über eine solche Funktion.
Die Nachteile:
Nun ... wer weiß, ob Bash unter OS X verfügbar ist?
quelle