ls -1
listet meine Elemente so auf:
foo.png
bar.png
foobar.png
...
Ich möchte, dass es ohne .png
ähnliches aufgelistet wird :
foo
bar
foobar
...
(das Verzeichnis enthält nur .png
Dateien)
Kann mir jemand sagen, wie man grep
in diesem Fall verwendet?
Zweck: Ich habe eine Textdatei, in der alle Namen ohne die Erweiterung aufgelistet sind. Ich möchte ein Skript erstellen, das die Textdatei mit dem Ordner vergleicht, um festzustellen, welche Datei fehlt.
.
. Obwohl die Konvention besagt, dass Sie Ihre Dateien.png
am Ende mit einem Namen versehen sollen, gibt es keinen Grund, warum ich keine PNG-Datei mit dem Namenfoo.zip
odermy.picture.20160518
oder einfach haben kannmypic
.ls
und zu Rohr des Ausgangsls
undfind
, vor allem , weil die Möglichkeit , in entstehennewline
, `Tab Zeichen im Dateinamen. Wenn der DateinameThe new art of working on .png\NEWLINE files and other formats
viele der vorgeschlagenen Lösungen enthält, treten Probleme auf.Antworten:
Sie benötigen nur die Shell für diesen Job.
POSIXly:
Mit
zsh
:quelle
printf
;echo ${f%.png}
wird genügen.Der
sed
Befehl entfernt (dh ersetzt durch die leere Zeichenfolge) alle Zeichenfolgen,.png
die am Ende eines Dateinamens stehen.Das
.
wird\.
so maskiert , dass es als Literalzeichen und nicht als regulärer Ausdruck interpretiert wird (was bedeutet , dass es mitsed
einem beliebigen Zeichen übereinstimmt). Das ist der Zeilenende-Anker, daher stimmt er nicht in der Mitte eines Dateinamens überein ..
.
$
.png
quelle
sed 's/\.[^.]*$//'
-1
ist nicht erforderlich, da dies die Standardeinstellung ist.-1
spezifiziert werden sollte. Dies ist nur die Standardeinstellung, wenn die Pipe eingeschaltet ist, was für manche eine versteckte Überraschung ist. Das Ausdrücken hilft also zu verstehen. Ich mache das auch in meinen Skripten, damit ich weiß, welche Art von Ausgabe ich erwarte..png
) vor einem Zeilenumbruchzeichen wird auch dieser.png
und nicht nur der letzte gelöscht . Es ist besser zu vermeiden, die Ausgabe von ls zu leiten und zu analysieren, da dies häufig gut versteckte Überraschungen birgt ... (einige Wörter und Verweise mehr in der Antwort).Wenn Sie nur bash verwenden möchten:
Sie sollten
grep
bei der Suche nach Übereinstimmungen nach greifen , nicht nach Entfernen / Ersetzensed
:Sobald Sie sich entschlossen haben, einige Unterverzeichnisse zu erstellen, um Ordnung in Ihre PNG-Dateien zu bringen, können Sie dies leicht ändern in:
quelle
find
Weiterleitung zursed
Lösung kann einige Probleme verursachen, wenn Sie eine Datei mit dem Schlüssel (.png
) als Teil des Namens und kurz vor einem Zeilenumbruch finden. Es ist besser zu vermeiden, die Ausgabe vonfind
oder zu leiten und zu analysierenls
, es behält sich oft gut versteckte Überraschungen vor ... (einige Wörter und Verweise mehr in der Antwort).find
etwas wieecho
im letzten Beispiel ersetzen . Nicht klar, welchen Zweck esfind
gibt und die Ergebnisse hängen von der Verzeichnisstruktur ab (dh, wenn Sie ein Verzeichnis habenfiles.png
)Ich würde gehen
basename
(unter der Annahme der GNU-Implementierung):quelle
-z
(oder--zero
) des GNU-Basisnamens zu verwenden, um eine durch NUL getrennte (anstelle einer durch Zeilenumbrüche getrennten) Ausgabe zu erzeugen.Eine andere sehr ähnliche Antwort (ich bin überrascht, dass diese bestimmte Variante noch nicht erschienen ist) ist:
-1
Option nicht aktivierenls
, dals
davon ausgegangen wird, dass die Standardausgabe kein Terminal ist (in diesem Fall eine Pipe).-n
Optionsed
bedeutet "Die Zeile nicht standardmäßig drucken"./p
Option am Ende der Ersetzung bedeutet "... und diese Zeile ausdrucken, wenn eine Ersetzung vorgenommen wurde".Der Nettoeffekt davon besteht darin, nur die Zeilen auszudrucken, die
.png
mit dem.png
entfernten enden . Das heißt, dies trägt auch der leichten Verallgemeinerung der Frage des OP Rechnung, bei der das Verzeichnis nicht nur.png
Dateien enthält.Die
sed -n
Technik ist häufig in Fällen nützlich, in denen Sie andernfalls grep + sed verwenden könnten.quelle
.png
) vor dem Zeilenumbruchzeichen böser ist: In diesem Fall drucken Sie diesen Teil ohne png und löschen nicht nur den letzten Teil. Es wird oftmals empfohlen, die Ausgabe nicht zu analysieren (und zu leiten),ls
da die Probleme nur dort versteckt werden können, wo Sie nicht darüber nachdenken ...find
oder - möglicherweise besser - nutzen Sie eine leistungsfähigere Sprache alssh
sie zu verwalten (die Tatsache , dasssh
kann alles tun , bedeutet nicht , dass es die beste Wahl in jeder Fall). Die Shell ist zunächst auf Benutzerfreundlichkeit ausgelegt.ls
, aber es gibt Probleme für die Zukunft. Oft machen wir Skripte, die wir später verwenden werden, wenn wir ihr Limit schon vergessen haben ... (es ist menschlich, es ist üblich). Ich schlug einfind
Beispiel (mit-exec
und ohne Pfeife) vor, auch wenn ich der Meinung bin, dass eine bessere (weil reine Schale) Antwort auf die eine , feste und posix-konforme Antwort des Cuonglms ist .locate
odermake
.Sie können dazu nur BASH-Befehle verwenden (ohne externe Tools).
Dies ist nützlich, wenn Sie ohne / usr / bin sind und für Dateinamen wie this.is.image.png und für alle Erweiterungen geeignet sind.
quelle
Es ist nicht sicher zu analysieren
ls
oder zu leitenfind
[ 1 , 2 ]Es ist nicht sicher, die Ausgabe von
ls
oder zu analysieren (und zu leiten)find
, hauptsächlich, weil es möglich ist, in den Dateinamen nicht übliche Zeichen als Zeilenumbruch zu finden , die Registerkarte ... Hier funktioniert ein reiner Shell-Zyklus [ cuonglm ] .Auch der
find
Befehl verrohrt nicht mit der Option-exec
funktioniert:Updates / Hinweise : Mit können Sie
find .
auch nach versteckten Dateien suchen oderfind ./*.png
nur nach nicht versteckten. Beifind *.png -exec ...
Ihnen kann es zu Problemen kommen, falls eine Datei mit dem Namen ".png
find" vorhanden war. Diese wird von find als Option abgerufen. Sie können hinzufügen-maxdepth 0
, um zu vermeiden, dass in Verzeichnissen mit dem NamenDir_01.png
oderfind ./*.png -prune -exec ...
wenn maxdepth nicht zulässig ist (danke Stéphane) , absteigend verfahren wird. Wenn Sie vermeiden möchten, diese Verzeichnisse aufzulisten, sollten Sie die Option hinzufügen-type f
(die auch andere Arten von nicht regulären Dateien ausschließt). Werfen Sie einen Blick auf,man
um ein umfassenderes Panorama über alle verfügbaren Optionen zu erhalten, und prüfen Sie, ob diese POSIX-kompatibel sind, um die Portabilität zu verbessern.Noch ein paar Worte
Es kann beispielsweise vorkommen, dass beim Kopieren des Titels aus einem Dokument und Einfügen in den Dateinamen eine oder mehrere Zeilenvorschübe im Dateinamen selbst abgeschlossen werden. Wir können sogar so unglücklich sein, dass ein Titel sogar den Schlüssel enthalten kann, den wir kurz vor einer neuen Zeile verwenden müssen:
Wenn Sie testen möchten, können Sie mit den Befehlen solche Dateinamen erstellen
Das einfache
/bin/ls *png
wird?
anstelle der nicht druckbaren Zeichen ausgegebenIn allen Fällen, in denen Sie die Ausgabe von
ls
oderfind
den folgenden Befehl weiterleiten, gibt es keinen Hinweis darauf, ob die aktuelle Zeile aus einem neuen Dateinamen stammt oder einem Zeilenumbruchzeichen im vorhergehenden Dateinamen folgt . Ein böser Name, aber immer noch ein legaler.Ein Shell-Zyklus mit einer Shell-Parameter-Erweiterung,
${parameter%word}
in beiden Varianten mitprintf
oderecho
wird funktionieren [ cuonglm ], [ Anthon1 ] .Aus der Manpage der Shell Parameter Expansion [ 3 ]
quelle
find
Befehls sind ein wenig variabel (zum Beispiel, wenn es ein Verzeichnis namens gibtfiles.png
)bash 4.3.11
, dash 0.5.7-4, zsh (wenn nötig) 5.0.2 durchgeführt. Fühlen Sie sich frei, diesen Beitrag zu lesen , der etwas mehr hinzufügt. Ich stimme dem Hinweis zu, die Ausgabe von zu leitenfind
, was ich ausdrücklich vorgeschlagen habe-exec
, und habe im Titel geschrieben.:-)
.ls
gibt es keinerlei Probleme, wenn die Ausgabe weitergeleitet oder umgeleitet wird, aber wie im Wiki erwähnt, funktioniert dies möglicherweise nicht für alle. Die meisten fügen?
Sonderzeichen nur ein, wenn die Ausgabe an das Terminal gesendet wird. dh tunecho *.png | od -c
undls *.png | od -c
. Das Newline-Problem ist kein Problemls
, es ist ein Problem mit jedem Befehl, der nicht auf beiden Seiten der Pipe mit Null endet.printf "${f%.png}\n"
ist falsch. Das erste Argument ist das Format, Sie sollten dort keine variablen Daten verwenden. Kann sogar als DoS-Sicherheitslücke angesehen werden (versuchen Sie es beispielsweise mit einer%1000000000s.png
Datei).find ./*.png -prune -exec...
oder Sie hätten Probleme mit Dateinamen beginnend mit-
(und Dateien vom Typ Verzeichnis, beachten Sie, dass-maxdepth
nicht portierbar ist)war es nicht genug
oder im Allgemeinen dies
entfernt alle Erweiterungen
quelle
-1
ist nicht erforderlich, da dies die Standardeinstellung ist.ls
es geht trotzdem ohne diese Option, wenn sein Ausgang kein Terminal ist, was hier der Fall ist.Verwendung
rev
:rev
kehrt alle Zeichenfolgen (Linien) um; du schneidest alles nach dem ersten '.' und rev kehrt den Rest um.Wenn du
grep
'alma' willst :quelle
-1
ist nicht erforderlich, da dies die Standardeinstellung ist.My.2016.Summer.Vacation.png
cut -f 2-
.png
und einer neuen Zeile gleich danach ... Es wird empfohlen, das Parsen zu vermeiden,ls
da es die Überraschungen gut verbergen mag ... :-)Wenn ich gewusst hätte, dass das Verzeichnis nur Dateien mit der Erweiterung .png enthält, hätte ich Folgendes ausgeführt:
ls | awk -F. '{print $1}'
Dies gibt das erste "Feld" für alles zurück, wo sich eine Dateinamenerweiterung befindet.
Beispiel:
quelle
.
, wieImage.1.png
und auch auf diejenigen , die mit nicht schön Namen , mit Sonderzeichen im Inneren. als Neue - Zeile oder diejenige , die man als (Eingangs-) -Eintrag Separator in der Anwendung wirdawk
,RS
. Es wird empfohlen, das Parsen derls
Ausgabe zu vermeiden, da Probleme, die auftreten, wenn Sie sie nicht erwarten, gerne ausgeblendet werden. Sie können mehr in den Referenzen 1 oder 2 lesen . BTW nice die Idee, awk zu verwenden ... Ich habe einige Beispiele in einer Antwort..
in\.
in der entkommensed -e 's/\.png$//'
, aber so wird es eine Antwort, die gerade geschrieben wurde. :-( note2 Sie können versuchen, esawk
mit so etwas wiels | awk -F. '{if ($NF=="png") {for (i=1;i<NF-1;i++) printf("%s.", $i) ; printf $(NF-1)"\n"}}'
... zu verwenden, aber Sie werden immer das Problem haben, dass awk nicht wissen kann, ob die angekommene Zeile einer neuen Zeile im Dateinamen folgt oder nicht. Ich habe versucht, dies in meiner Antwort besser auszudrücken .Laut Ihrem Kommentar "Ich habe eine Textdatei, in der alle Namen ohne die Erweiterung aufgeführt sind. Ich möchte ein PHP-Skript erstellen, das die Textdatei mit dem Ordner vergleicht, um festzustellen, welche Datei fehlt":
und umgekehrt:
quelle
ls -l | sed 's/\.png$//'
Ist die genaueste Methode, die von @roaima hervorgehoben wird. Ohne die entkam
\.png
Dateien mit dem Namena_png.png
würde wie folgt aufgelistet:a_
.quelle
ls -l
, wie Sie es tun, gibt die Datei Details, das ist nicht, was das OP gefragt hat.Eine einfache Shell-Zeile (ksh, bash oder zsh; nicht dash):
Eine einfache Funktion (von No Extension):
Oder eine Funktion, die alle angegebenen Erweiterungen entfernt (standardmäßig png):
Benutzen als:
Wenn es sich bei der Ausgabe um ein Sternchen handelt
*
, ist keine Datei mit dieser Erweiterung vorhanden.quelle
Sie können den folgenden Feed probieren, wenn die Ausgabe Ihres Superators das "." Ist. Und da alle Ihre Dateien name.png haben, drucken Sie die erste Spalte:
ls | awk -F"." '{print $1}'
quelle
Wenn Sie Zugriff auf sed haben, ist dies besser, da es die letzte Dateierweiterung entfernt, egal was es ist (png, jpg, tiff, etc ...)
quelle
this.is.a.dotty.txt
. Versuchen Sie ess/\.[^.]*$//
stattdessen.