' ls -1 ': Auflisten von Dateinamen ohne Erweiterung

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 kann foo.zip oder my.picture.20160518 oder nur mypic.
  • @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 von ls und find weiterzuleiten, hauptsächlich wegen der Möglichkeit, in newline,` tab char im Dateinamen. Wenn der Dateiname The 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 an sed 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 vonfindoderlszu leiten und zu analysieren, da sie oft gut versteckte Überraschungen reserviert … (einige Wörter und verweist mehr auf die Antwort).

  • Ersetzen Sie wahrscheinlich 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)
  • @BroSlow Auf etwas Vernünftigeres aktualisiert.
  • 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 zu ls, da ls davon ausgeht, dass die Standardausgabe kein „Terminal“ ist (in diesem Fall „Pipe“).
    • Die Option -n für sed 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 von ls, 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 als sh, um sie zu verwalten (die Tatsache, dass sh 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 ein find 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 Dateiname Image.png.jpg.png den Schlüssel ständig schneidet (.png). Unter Unix sind seltsame Dateinamen als The 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 die ls -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 Namen files.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 von find 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 und ls *.png | od -c. Das Newline-Problem ist kein Problem mit ls, 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 ., als Image.1.png und sogar bei denen mit nicht nett Namen mit Sonderzeichen. als Zeilenumbruch oder als Zeile, die Sie als (Eingabe-) Datensatztrennzeichen in awk, RS verwenden. Es wird empfohlen, die Ausgabe von ls 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 der sed -e 's/\.png$//', aber so wird es eine Antwort, die gerade geschrieben wurde. 🙁 note2 Sie können versuchen, awk mit etwas wie ls | 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 stattdessen s/\.[^.]*$//.

    Schreibe einen Kommentar

    Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.