`xargs` mit Leerzeichen in Dateinamen

7

Ich versuche, nur Nicht-Bilddateien aufzulisten und nur in den letzten 500 Dateien zu suchen. Also renne ich

ls -t | head -500 | file | grep -v 'image'

was nicht richtig ist: es zeigt eine Hilfemeldung an. Ändern in

ls -t | head -500 | xargs file | grep -v 'image'

Ich jetzt manchmal die Ausgabe erhalte ich will, aber wenn der Dateiname Leerzeichen in es-zum Beispiel hat Plutonian\ Nights\ -\ Sun\ Ra.mp3-dann xargsläuft file Plutonian, file Nightsusw.


Wie kann ich entweder helfen xargs, die Räume zu sehen, oder auf andere Weise das erreichen, was ich erreichen möchte ?

Isomorphismen
quelle
In gängigen xargsImplementierungen kann das Trennzeichen beispielsweise in geändert werden '\n'. Dies ist häufig hilfreich, wenn die Eingabe nicht von generiert wird find. Siehe -d(GNU) und -E(OSX)
MattBianco

Antworten:

5

Unter Verwendung xargs, kann es auf diese Weise durchgeführt werden:

find . -type f -print0 | xargs -0 file | grep -v 'image' 

Ist xargsaber so gestern. Die coolen Kids benutzen parallelheute. Mit parallel wäre es:

find . -type f | parallel file | grep -v 'image'

Sehen. Keine Verwendung von -print0 und -0. parallelist wirklich klug für sich.

AKTUALISIEREN

Um nur die letzten 500 Dateien aufzulisten, lautet Ihr Befehl:

ls -1t | head -500 | parallel file {} | grep -v image

Wichtig

Wenn Ihre Parallele alt ist und die obige Syntax nicht funktioniert, installieren Sie die neue Version von Parallel wie hier beschrieben: http://www.gnu.org/software/parallel/parallel_tutorial.html

Shivams
quelle
2

Verwenden Sie "find" mit der Option "-print0" und leiten Sie die Ausgabe mit der Option "-0" an "xargs" weiter.

Obwohl ich diese Technik kenne (und verwende), sehe ich, dass Benutzer @Jens eine ähnliche Frage beantwortet hat, wo Sie weitere Details finden können:

/programming/16758525/use-xargs-with-filenames-containing-whitespaces

Prem
quelle
1
Du hast die tief hängenden Früchte. Wie durchsucht man nur die letzten 500 Dateien?
G-Man sagt "Reinstate Monica"
1

Ich habe zwei grobe Vorschläge, die helfen könnten. Beides fühlt sich jedoch nicht besonders befriedigend an, sodass vielleicht etwas Besseres herauskommt.

Verwenden Sie zunächst sed, um Anführungszeichen zu allem hinzuzufügen, sodass Sie nur dann Probleme haben, wenn der Dateiname Anführungszeichen wie enthält

ls -t | head -500 | sed -e 's/\(.*\)/"\1"/' | xargs file | grep -v 'image'

Die andere ist, die ls zu verwenden, um die 501. neueste zu finden, und dann find zu verwenden, um die neueren Sachen wie zu erhalten

find -newer $(ls -t | head -501 | tail -1) -type f -exec file {} \; | grep -v image
Eric Renouf
quelle
1
Solange wir die Ausgabe von ls analysieren, wird Ihr erstes Snippet meiner Meinung nach verbessert, indem Sie Zeilenumbrüche durch nulls ( tr \\n \\0) ersetzen und verwenden xargs -0.
Dhag
1

Allgemeine Hinweise zur Verarbeitung von Dateinamen, die möglicherweise Leerzeichen enthalten, finden Sie unter Warum verschluckt sich mein Shell-Skript an Leerzeichen oder anderen Sonderzeichen?

Die Schwierigkeit bei dem, was Sie versuchen, besteht darin, dass es keine gute Möglichkeit gibt, die N neuesten Dateien mit Standardwerkzeugen aufzulisten.

Der einfachste Weg, das zu tun, was Sie hier tun, besteht darin, zsh als Shell zu verwenden. Es verfügt über Glob-Qualifizierer zum Sortieren von Dateien nach Datum. So führen Sie filedie 500 neuesten Dateien aus:

file *(om[1,500])

Übergeben Sie mit dem Linux- fileDienstprogramm die Option -ioder --mime-type, um eine Ausgabe zu erhalten, die einfacher zu analysieren ist. Bilddateien werden durch Zeilen gekennzeichnet, die mit enden image/something.

file --mime-type *(om[1,500]) | sed -n 's~: *image/[^ ]*$~~p'

Wenn Sie mit absolut allen Dateinamen fertig werden müssen, einschließlich derer mit einem Zeilenumbruch im Namen, verwenden Sie die -0Option für eine durch Nullen getrennte Ausgabe. Neuere Versionen von GNU sed können anstelle von Zeilenumbrüchen Null-Bytes als Datensatztrennzeichen verwenden.

file --mime-type -- *(om[1,500]) | sed -zn 's~: *image/[^ ]*$~~p'

Wenn Sie nicht über zsh verfügen, können Sie lsDateinamen verwenden und verarbeiten, die Leerzeichen, aber keine Zeilenumbrüche oder nachgestellten Leerzeichen enthalten, indem Sie die -L1Option an übergeben file. Dies wird jeweils filefür eine Datei aufgerufen , ist also etwas langsamer.

ls -t | head -n 500 | xargs -L1 file --mime-type -- | sed -n 's~: *image/[^ ]*$~~p'
Gilles 'SO - hör auf böse zu sein'
quelle
-1

Sie könnten es versuchen

printf "%s\0" $(ls -t | head -500) | xargs -0 file | grep -v image

Dies zwingt xargs, die Dateinamenargumente auf Null zu setzen.

doneal24
quelle
1
Wenn ich dies mit einer Datei versuche, deren Name Leerzeichen enthält (z. B. Sun Ra), wird dies angezeigt Sun\0Ra\0, sodass das Problem dadurch nicht gelöst wird.
G-Man sagt "Reinstate Monica"
Entschuldigung, ich habe eine Reihe von Zitaten verpasst:
doneal24
1
Dies wird nicht funktionieren; printfwird jedes durch Leerzeichen getrennte Wort als Argument betrachten. Sie können dies mit testen printf "%s\n" $(printf "file #1\nfile2\n").
Dhag
@dhag: Ja, darauf habe ich vor 40 Minuten hingewiesen.
G-Man sagt "Reinstate Monica"
1
@Doug: Wenn Sie eine schrittweise Verfeinerung von Erics Antwort vorschlagen möchten, ist es sinnvoller, dies in einem Kommentar zu Erics Antwort zu tun - und zu erklären, warum Ihre Antwort besser ist als seine. Außerdem haben Sie den imageTeil der Frage verpasst .
G-Man sagt "Reinstate Monica"