ls -1
listet meine Elemente folgendermaßen auf:
foo.png bar.png foobar.png ...
Ich möchte, dass sie ohne wie folgt:
foo bar foobar ...
(das Verzeichnis enthält nur .png
Dateien)
Kann mir jemand sagen, wie man in diesem Fall grep
verwendet?
Zweck: Ich habe eine Textdatei, in der alle Namen ohne die aufgeführt sind Erweiterung. Ich möchte ein Skript erstellen, das die Textdatei mit dem Ordner vergleicht, um festzustellen, welche Datei fehlt.
Kommentare
- Sie möchten vorsichtig sein eine Anfrage wie diese. Linux hat keine Dateinamenerweiterungen. Linux enthält Dateinamen, die möglicherweise eine
.
enthalten. Obwohl die Konvention besagt, dass Ihre Dateien am Ende mit.png
benannt werden sollen, gibt es keinen Grund, warum ich ‚ keine PNG-Datei mit dem Namen haben kannfoo.zip
odermy.picture.20160518
oder nurmypic
. - @hymie I. Ich weiß, aber meine Elemente in diesem Ordner sind alle mit .png am Ende benannt.
- Was ‚ ist ein “ Erweiterung „? Das ‚ ist nicht Teil der Unix-Dateinamen; ‚ ist eine Übertragung von VMS / NT / Windows. Und Sie Jugendlichen steigen auch von meinem Rasen. 🙂
- Lassen Sie ‚ dies nicht übertreiben. Das Betriebssystem behandelt Erweiterungen einfach als Teil des Dateinamens, aber viele Unix-Programme achten darauf, vom Compiler bis zur GUI. Das Konzept ist Unix mit Sicherheit nicht fremd.
- Es wird normalerweise empfohlen, zu vermeiden, die Ausgabe von
ls
und um die Ausgabe vonls
undfind
weiterzuleiten, hauptsächlich wegen der Möglichkeit, innewline
,` tab char im Dateinamen. Wenn der DateinameThe new art of working on .png\NEWLINE files and other formats
lautet, führen viele der vorgeschlagenen Lösungen zu Problemen.
Antwort
Sie benötigen nur die Shell für diesen Job.
POSIX:
for f in *.png; do printf "%s\n" "${f%.png}" done
Mit zsh
:
print -rl -- *.png(:r)
Kommentare
- Dort ‚ benötigt keine
printf
;echo ${f%.png}
reicht aus. - @Conrad: Die Verwendung von echo ‚ funktioniert in einigen Fällen nicht richtig, wenn der Dateiname Beginnen Sie mit einem Bindestrich oder enthalten Sie maskierte Sequenzen.
- @DavidConrad: Siehe auch unix.stackexchange.com/a/65819/38906
- @DavidConrad Außerdem glaube ich, dass printf eingebaut ist, genau wie Echo. Jemand korrigiert mich, wenn ich ‚ falsch
bin
Antwort
ls -1 | sed -e "s/\.png$//"
Der Befehl sed
entfernt (dh es ersetzt durch die leere Zeichenfolge) jede Zeichenfolge .png
, die am Ende von gefunden wurde ein Dateiname.
Die .
wird als \.
maskiert, sodass sie von als Literal .
und nicht als regulärer Ausdruck .
(was bedeutet, dass eine beliebige ch übereinstimmt aracter). Der $
ist der Zeilenende-Anker, daher stimmt er nicht mit .png
in der Mitte eines Dateinamens überein. P. >
Kommentare
- Ich denke, das OP möchte, dass jede Erweiterung entfernt wird, aber wahrscheinlich nur die “ letzte „. Ändern Sie also Ihre ansonsten gute Antwort möglicherweise mit:
sed 's/\.[^.]*$//'
- Ja, diese Regexp würde Arbeiten Sie in diesem Fall … aber wenn das OP dies wünscht, sollten sie dies sagen, anstatt ausdrücklich zu sagen, dass “ es ohne die .png “
- Die
-1
ist nicht erforderlich, da dies die Standardeinstellung ist. - @jlliagre Ich stimme cas zu, dass die
-1
sollte angegeben werden. ‚ ist nur die Standardeinstellung, wenn die Pipe eingeschaltet ist, was für einige eine versteckte Überraschung ist Ich mache das auch in meinen Skripten, damit ich weiß, was für ein o utput I ‚ Ich erwarte. - Warnung Bei einem Dateinamen mit dem Schlüssel (
.png
) Vor einem Zeilenumbruch löschen Sie sogar das.png
und nicht nur das letzte. Es ist besser zu vermeiden, die Ausgabe von ls zu pfeifen und zu analysieren, es reserviert oft gut versteckte Überraschungen … (einige Wörter und Verweise mehr in der Antwort).
Antwort
Wenn Sie nur bash verwenden möchten:
for i in *; do echo "${i%.png}"; done
Sie sollten nach grep
greifen, wenn Sie versuchen, Übereinstimmungen zu finden, und nicht, um diese zu entfernen / zu ersetzen. sed
ist besser geeignet:
find . -maxdepth 1 -name "*.png" | sed "s/\.png$//"
Wenn Sie sich entschieden haben, einige Unterverzeichnisse zu erstellen, um Ordnung in Ihre PNG-Dateien zu bringen, können Sie dies einfach ändern in:
find . -name "*.png" | sed "s/\.png$//"
Kommentare
- ls -1 | sed ‚ s / .png // ‚ funktioniert hervorragend. Vielen Dank!
- Die
find
ansed
weitergeleitete
Lösung kann einige Probleme aufwerfen, wenn Sie finden eine Datei mit dem Schlüssel (.png
) als Teil des Namens und kurz vor einem Zeilenumbruchzeichen. Es ist besser zu vermeiden, die Ausgabe vonfind
oderls
zu leiten und zu analysieren, da sie oft gut versteckte Überraschungen reserviert … (einige Wörter und verweist mehr auf die Antwort).
find
durch etwas wie echo
im letzten Beispiel. Nicht klar, welchem Zweck find
dort dient, und die Ergebnisse hängen von der Verzeichnisstruktur ab (dh wenn Sie ein Verzeichnis files.png
haben) Antwort
Eine weitere sehr ähnliche Antwort (das überrascht mich) Eine bestimmte Variante, die noch nicht erschienen ist, ist:
ls | sed -n "s/\.png$//p"
- Sie benötigen die
-1
nicht Option zuls
, dals
davon ausgeht, dass die Standardausgabe kein „Terminal“ ist (in diesem Fall „Pipe“). - Die Option
-n
fürsed
bedeutet, dass die Zeile nicht standardmäßig gedruckt wird. - Die Option
/p
am Ende der Ersetzung bedeutet „… und drucke diese Zeile, wenn eine Ersetzung vorgenommen wurde“.
Das Netz Dies bewirkt, dass nur die Zeilen ausgedruckt werden, die mit .png
mit der entfernt. Dies bedeutet auch, dass die Frage des OP leicht verallgemeinert wird, wobei das Verzeichnis nicht nur .png
-Dateien enthält.
Die sed -n
Technik ist oft nützlich in Fällen, in denen Sie andernfalls grep + sed verwenden könnten.
Kommentare
- Ich mag, wie die Pflege Sie haben Ihre Antwort geschrieben. Diese Lösung führt zu Problemen mit Dateinamen, einschließlich Zeilenumbrüchen . Der erste Teil des Namens wird nicht gedruckt. Noch mehr, wenn es sich um einen unangenehmeren Teil mit dem Schlüssel (
.png
) vor dem Zeilenumbruch: In diesem Fall wird dieser Teil ohne PNG gedruckt, wobei nicht nur der letzte Teil gelöscht wird. Es wird häufig empfohlen, die Ausgabe vonls
, da die Probleme nur dort ausgeblendet werden können, wo Sie nicht darüber nachdenken … - @Hastur Sie ‚ sind korrekt im Prinzip und die berühmte Seite über don ‚ t parse ls listet weitere Probleme (und Lösungen) bei der Übergabe pathologischer Dateinamen auf. Aber die beste Art, damit umzugehen, besteht darin, pathologische Dateinamen zu vermeiden (doh!); und wenn Sie ‚ t können oder wenn Sie gegen sie robust sein müssen, verwenden Sie entweder
find
oder – möglicherweise besser – Verwenden Sie eine leistungsfähigere Sprache alssh
, um sie zu verwalten (die Tatsache, dasssh
dies kann Alles bedeutet nicht, dass ‚ nicht bedeutet, dass ‚ jeweils die beste Wahl ist. Die Shell ist zuerst auf Benutzerfreundlichkeit ausgelegt. - Ich stimme im Prinzip der Benutzerfreundlichkeit zu, aber diese Variante schlägt fehl, wenn Sie mit jeder neuen Zeile einen Dateinamen haben. Dies kann leicht unbemerkt auftreten, beispielsweise wenn Sie eine Zeile aus einem PDF in eine GUI kopieren und einfügen. Sie denken also nur, dass pathologische Dateinamen vermieden werden sollten.
- Außerdem IMHO Es ist ‚ einfach,
ls
zu analysieren, aber es sind zukünftige Probleme im Gange. Oft erstellen wir Skripte das wir später verwenden werden, wenn wir ihr Limit bereits vergessen … (es ist ‚ menschlich, es ist ‚ üblich). Ich schlug einfind
Beispiel vor (mit-exec
und ohne Pipe) Selbst wenn ich eine bessere (weil reine Shell) Antwort finde, ist die Antwort cuonglm ‚ solide und posix-konform. - Dies ist so ziemlich das, was ich ‚ tun würde, wenn ich aus irgendeinem Grund die
.png
Suffix aus einer Liste von Dateinamen.Ich würde es nicht ‚ in ein Skript einfügen. Stattdessen würde ich ‚ einfach den Befehl an der Shell-Eingabeaufforderung eingeben. Dies wäre eine Erinnerung daran, dass ich ‚ m unter der Annahme “ vernünftig “ Dateinamen. Es gibt viele Dinge, die ich ‚ in einem einmaligen manuellen Befehl tun werde, wenn ich frei bin, Annahmen darüber zu treffen, was ‚ ist im aktuellen Verzeichnis würde ich ‚ wahrscheinlich nicht in einem Skript tun, das in einem anderen Kontext wiederverwendet werden könnte.
Antwort
Ich würde mich für basename
entscheiden (unter der Annahme der GNU-Implementierung):
basename --suffix=.png -- *.png
Kommentare
- Beachten Sie, dass die Verwendung des GNU-Basisnamens ‚ s
-z
(oder--zero
) Option zum Erzeugen von NUL-getrennt (anstelle von Zeilenumbruch) ) Ausgabe.
Antwort
Sie können dazu nur BASH-Befehle verwenden (ohne externe Tools).
for file in *; do echo "${file%.*}"; done
Dies ist nützlich, wenn Sie ohne / usr / bin sind und für Dateinamen l gut funktionieren ike this.is.image.png und für alle Erweiterungen.
Antwort
war es nicht genug?
ls -1 | sed "s/\.png//g"
oder im Allgemeinen entfernt dieses
ls -1 | sed "s/\.[a-z]*//g"
alle Erweiterungen
Kommentare
- Es war, aber die anderen Lösungen funktionieren auch.
- Auf allen Unix / Unix Like-Systemen ist (oder sollte)
sed
installiert, da dies ein obligatorisches Dienstprogramm ist Standardmäßig. - In der Tat, aber
ls
macht es trotzdem ohne diese Option, wenn seine Ausgabe kein Terminal ist, was hier der Fall ist. - Warnung
ls -1 | sed 's/\.[a-z]*//g'
schlägt fehl, wenn der DateinameImage.png.jpg.png
den Schlüssel ständig schneidet (.png
). Unter Unix sind seltsame Dateinamen alsThe new art of working on .png?files and other formats.png
zulässig, wobei die?
ist ein Zeilenumbruchzeichen. Leider wird die gesamte Lösung, die einfach diels
-Ausgabe leitet / analysiert, problematisch sein ms, die solche Fälle verwalten … - Warum das Qualifikationsmerkmal
g
? Sie möchten\.png
nur am Ende der Zeile entfernen, nicht jedes Mal, wenn es angezeigt wird.
Antwort
Es ist nicht sicher, ls
zu analysieren oder find
[ 1 , 2 ]
Dies ist nicht sicher Analysieren (und Weiterleiten) der Ausgabe von ls
oder find
, hauptsächlich, weil es möglich ist, in den Dateinamen nicht übliche Zeichen wie newline , tab … Hier funktioniert ein reiner Shell-Zyklus [ cuonglm ] .
Auch der Befehl find
wird nicht mit der Option -exec
funktioniert:
find ./*.png -exec basename {} .png \;
Updates / Hinweise : Sie können find .
verwenden, um auch nach versteckten Dateien zu suchen, oder find ./*.png
nur die nicht versteckten zu bekommen. Mit find *.png -exec ...
können Sie Probleme haben, wenn eine Datei mit dem Namen .png
vorhanden war, da find diese als Option erhält. Sie können -maxdepth 0
hinzufügen, um zu vermeiden, dass Sie in Verzeichnissen mit dem Namen Dir_01.png
oder find ./*.png -prune -exec ...
absteigen maxdepth ist nicht erlaubt (danke Stéphane). Wenn Sie vermeiden möchten, diese Verzeichnisse aufzulisten, sollten Sie die Option -type f
hinzufügen (die auch andere Arten nicht regulärer Dateien ausschließen würde). Schauen Sie sich die man
an, um ein vollständigeres Panorama aller verfügbaren Optionen zu erhalten, und prüfen Sie, ob sie POSIX-kompatibel sind, um eine bessere Portabilität zu erzielen.
Einige Wörter mehr
Es kann beispielsweise vorkommen, dass beim Kopieren des Titels aus einem Dokument und Einfügen in den Dateinamen eine oder mehrere Zeilenumbrüche im Dateinamen selbst beendet werden.Wir können sogar so viel Pech haben, dass ein Titel sogar den Schlüssel enthalten kann, den wir kurz vor einer neuen Zeile verwenden müssen:
The new art of working on .png files and other formats.
Wenn Sie testen möchten, können Sie dies Erstellen Sie solche Dateinamen mit den Befehlen
touch "A file with two lines"$"\n""and This is the second.png" touch "The new art of working on .png"$"\n""files and other formats.png"
Die einfache /bin/ls *png
gibt anstelle der nicht druckbaren Zeichen
A file with two lines?and This is the second.png The new art of working on .png?files and other formats.png
In allen Fällen, in denen Sie ausführen Pipe die Ausgabe von ls
oder find
Der folgende Befehl hat keinen Hinweis zu verstehen wenn die aktuelle Zeile von einem neuen Dateinamen stammt oder wenn sie einem Zeilenumbruch im vorhergehenden Dateinamen folgt. Ein böser Name, aber immer noch ein legaler.
Ein Shell-Zyklus mit einer Shell-Parametererweiterung, ${parameter%word}
, in beiden Die Variante mit printf
oder echo
funktioniert [ cuonglm ], [ Anthon1 ] .
for f in *.png; do printf "%s\n" "${f%.png}" ; done
Auf der Manpage der Shell-Parametererweiterung [ 3 ]
$ {parameter% word}
$ {parameter %% word}… das Ergebnis der Erweiterung ist der Wert des Parameters mit dem kürzesten Übereinstimmungsmuster (der Fall %) oder der Das längste übereinstimmende Muster (der Fall %%) wurde gelöscht.
Kommentare
- Auch die Ergebnisse Ihrer
find
ist eine Bitvariable (zum Beispiel, wenn es ein Verzeichnis mit dem Namenfiles.png
gibt) - Lieber @BroSlow, als ich die Antwort über I geschrieben habe versuchte 13 (alle) der anderen in diesem Moment vorhandenen Varianten per Befehlszeile in einem Skript, das als Argument eines Shell-Aufrufs gestartet wurde. Bitte machen Sie dasselbe und sagen Sie mir, ob sie sich so verhalten, wie Sie es erwarten. Ich habe meine Tests mit
bash 4.3.11
, Bindestrich 0.5.7-4, zsh (falls erforderlich) 5.0.2 durchgeführt. Fühlen Sie sich frei, diesen Beitrag zu lesen, der etwas mehr hinzufügt. Ich stimme dem Hinweis zu, dass die Ausgabe vonfind
weitergeleitet wird. Hierfür habe ich ausdrücklich-exec
vorgeschlagen und ich schrieb im Titel.:-)
. - Lesen Sie das Wiki erneut. Ich denke immer noch, dass Sie in Ihrem Beispiel eine Pipe erstellen müssen, da ‚ das ist, was ‚ hier diskutiert wird. Und für die meisten modernen Versionen von
ls
gibt es keinerlei Probleme, wenn die Ausgabe weitergeleitet oder umgeleitet wird, aber wie im Wiki erwähnt, funktioniert sie möglicherweise nicht für alle. Die meisten fügen nur die?
anstelle von Sonderzeichen ein, wenn die Ausgabe an das Terminal gesendet wird. d.h.echo *.png | od -c
undls *.png | od -c
. Das Newline-Problem ist kein Problem mitls
, es ist ‚ ein Problem mit einem Befehl, der nicht ‚ t null endet auf beiden Seiten der Pipe. -
printf "${f%.png}\n"
ist falsch. Das erste Argument ist das Format. ‚ sollte dort keine variablen Daten verwenden. Kann sogar als DoS-Sicherheitsanfälligkeit angesehen werden (versuchen Sie es beispielsweise mit einer%1000000000s.png
-Datei). - Sie ‚ d Benötigen Sie
find ./*.png -prune -exec...
oder Sie ‚ haben Probleme mit Dateinamen, die mit-
beginnen (und Dateien von Typ Verzeichnis, beachten Sie, dass-maxdepth
nicht portierbar ist)
Antwort
Verwenden Sie rev
:
ls -1 | rev | cut -f 2- -d "." | rev
rev
kehrt alle um Strings (Linien); Sie schneiden alles nach dem ersten „.“ und rev kehrt den Rest um.
Wenn Sie grep
„alma“ möchten:
ls -1 | rev | cut -f 2- -d "." | rev | grep "alma"
Kommentare
- Die
-1
ist nicht erforderlich, da dies die Standardeinstellung ist. - Dies schlägt bei einer Datei mit dem Namen
My.2016.Summer.Vacation.png
- @DavidConrad schlecht fehl: / Ich habe
cut -f 2-
- Jetzt funktioniert es mit dieser Datei, aber noch nicht mit einer Datei mit
.png
und einer neuen Zeile kurz danach … Es wird empfohlen, weil es liebt, die Überraschungen gut zu verbergen … 🙂
Antwort
Wenn ich gewusst hätte, dass das Verzeichnis nur Dateien mit der Erweiterung .png enthält, hätte ich einfach Folgendes ausgeführt: ls | awk -F. "{print $1}"
Dies gibt das erste „Feld“ für zurück alles, wo es eine Dateinamenerweiterung gibt.
Beispiel:
[rsingh@rule51 TESTDIR]$ ls 10.png 1.png 2.png 3.png 4.png 5.png 6.png 7.png 8.png 9.png [rsingh@rule51 TESTDIR]$ ls | awk -F. "{print $1}" 10 1 2 3 4 5 6 7 8 9
Kommentare
- Leider schlägt dies bei allen fehl die Dateinamen mit mehr als einem
.
, alsImage.1.png
und sogar bei denen mit nicht nett Namen mit Sonderzeichen. als Zeilenumbruch oder als Zeile, die Sie als (Eingabe-) Datensatztrennzeichen inawk
,RS
verwenden. Es wird empfohlen, die Ausgabe vonls
zu vermeiden, da Probleme, die auftreten, wenn Sie dies nicht erwarten, gerne ausgeblendet werden. Weitere Informationen finden Sie in der Referenz 1 oder 2 . Übrigens schön die Idee, awk zu verwenden … Ich habe einige Beispiele in einer Antwort zusammengefasst. - Richtig, aber angesichts des von Colin bereitgestellten Beispiels würde es gut funktionieren. Damit es für den von Ihnen vorgeschlagenen Fall funktioniert, würde ich es ‚ wahrscheinlich ändern in: [rsingh @ rule51 TESTDIR] $ ls | sed -e ‚ s / .png $ // ‚ 10 1 2 3 4 5 6 7 8 9 harry.the.bunny whats .a.png.filename Ich versuche nicht, schwierig zu sein, aber angesichts des Bedarfs von Colin ‚ bin ich ‚ nicht sicher, was das Problem sein würde ls analysieren.
- Entschuldigung … Ich habe gerade festgestellt, dass ich ‚ das Verzeichnis mit den Dateien nicht angezeigt habe, bevor ich die Ausgabe von ‚ ls ‚ [rsingh @ rule51 TESTDIR] $ ls 10.png 2.png 4.png 6.png 8.png harry.the.bunny. png 1.png 3.png 5.png 7.png 9.png whats.a.png.filename.png [rsingh @ rule51 TESTDIR] $ ls | sed -e ‚ s / .png $ // ‚ 10 1 2 3 4 5 6 7 8 9 harry.the.bunny whats .a.png.filename
- note1 Sie müssen die
.
in\.
innerhalb dersed -e 's/\.png$//'
, aber so wird es eine Antwort, die gerade geschrieben wurde. 🙁 note2 Sie können versuchen,awk
mit 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 haben Das Problem, dass awk nicht wissen kann, ob die Zeile ankommt, ist immer, dass eine neue Zeile im Dateinamen folgt oder nicht. Ich habe versucht, es in meiner Antwort besser zu sagen. - Danke Hastur, das habe ich verpasst :). Außerdem habe ich in diesem Fall die Verwendung von awk zugunsten von sed aufgegeben.
Antwort
gemäß Ihrer Kommentar „Ich habe eine Textdatei, in der alle Namen ohne die Erweiterung aufgelistet sind. Ich möchte ein PHP-Skript erstellen, das die Textdatei mit dem Ordner vergleicht, um festzustellen, welche Datei fehlt.“:
for file in $(cat yourlist) ; do [ -f "${file}.png" ] || { echo "$file : listed in yourlist, but missing in the directory" } done #assumes that filenames have no space... # otherwise use instead: # while IFS= read file ; do ...(same inner loop as above)... ; done < yourlist
und umgekehrt:
for file in *.png ; do grep "^${file%.png}$" yourlist >/dev/null || { echo "$file: present in the directory but not listed in yourlist" } done #I assume there are no spaces/tabs/? before/after names in "yourlist". Change the script accordingly if there are some (or sanitize the list)
Antwort
ls -l | sed "s/\.png$//"
Ist die genaueste Methode, die von @roaima hervorgehoben wird. Ohne die maskierten \.png
-Dateien mit dem Namen a_png.png
würden sie wie folgt aufgelistet: a_
. P. >
Kommentare
- mit
ls -l
gibt wie Sie die Dateidetails an, das hat das OP nicht verlangt ungefähr.
Antwort
Eine einfache Shell-Linie (ksh, bash oder zsh; kein Bindestrich):
set -- *.png; printf "%s\n" "${@%.png}"
Eine einfache Funktion (von No Extension):
ne(){ set -- *.png; printf "%s\n" "${@%.png}"; }
Oder eine Funktion, die entfernt wird Beliebige Erweiterung (standardmäßig PNG):
ne(){ ext=${1:-png}; set -- *."$ext"; printf "%s\n" "${@%.${ext}}"; }
Verwendung als:
ne jpg
Wenn die Ausgabe ein Sternchen *
ist, ist keine Datei mit dieser Erweiterung vorhanden.
Antwort
Sie können den folgenden Feed versuchen, wenn die Ausgabe von ls Ihr Superator das „.“ ist. und da alle Ihre Dateien name.png haben, drucken Sie die erste Spalte:
ls | awk -F"." "{print $1}"
Antwort
Wenn Sie Zugriff auf sed haben, ist dies besser, da die letzte Dateierweiterung entfernt wird, unabhängig davon, um was es sich handelt (png, jpg, tiff usw.)
ls | sed -e "s/\..*$//"
Kommentare
- Unterbrechungen für Dateinamen wie
this.is.a.dotty.txt
. Versuchen Sie stattdessens/\.[^.]*$//
.