Ich möchte den Dateinamen (ohne Erweiterung) und die Erweiterung separat erhalten.
Die beste Lösung, die ich bisher gefunden habe, ist:
NAME=`echo "$FILE" | cut -d'.' -f1`
EXTENSION=`echo "$FILE" | cut -d'.' -f2`
Dies ist falsch, da es nicht funktioniert, wenn der Dateiname mehrere .
Zeichen enthält . Wenn, sagen wir, ich habe a.b.js
, wird es a
und b.js
anstelle von a.b
und berücksichtigen js
.
Es kann leicht in Python mit gemacht werden
file, ext = os.path.splitext(path)
Ich würde es jedoch vorziehen, wenn möglich keinen Python-Interpreter nur dafür zu starten.
Irgendwelche besseren Ideen?
extension="{$filename##*.}"
wie ich es eine Weile getan habe! Bewegen Sie die$
Locken nach außen: Rechts:extension="${filename##*.}"
os.path.splitext
stattdessen für Pythons wie oben ...Antworten:
Holen Sie sich zuerst den Dateinamen ohne den Pfad:
Alternativ können Sie sich auf das letzte '/' des Pfads anstatt auf das '.' Konzentrieren. Dies sollte auch dann funktionieren, wenn Sie unvorhersehbare Dateierweiterungen haben:
Möglicherweise möchten Sie die Dokumentation überprüfen:
quelle
basename
extension=$([[ "$filename" = *.* ]] && echo ".${filename##*.}" || echo '')
. Beachten Sie, dass , wenn eine Erweiterung ist vorhanden, wird es mit dem anfänglichen zurückgeführt wird.
, zum Beispiel.txt
.Weitere Informationen finden Sie unter Erweiterung der Shell-Parameter im Bash-Handbuch.
quelle
dinosaurs.in.tar
und es aufdinosaurs.in.tar.gz
:)x.tar.gz
's Erweiterunggz
und der Dateiname istx.tar
das ist es. Es gibt keine doppelten Erweiterungen. Ich bin mir ziemlich sicher, dass boost :: filesystem so damit umgeht. (geteilter Pfad, change_extension ...) und sein Verhalten basiert auf Python, wenn ich mich nicht irre.Normalerweise kennen Sie die Erweiterung bereits, daher möchten Sie möglicherweise Folgendes verwenden:
zum Beispiel:
und wir bekommen
quelle
basename
ist ziemlich der Augenöffner, meine Güte, Sir / Madam :).zip
oder endet.ZIP
. Gibt es eine Möglichkeit, wie Sie so etwas tun könntenbasename $file {.zip,.ZIP}
?Sie können die Magie der POSIX-Parametererweiterung nutzen:
Es gibt eine Einschränkung darin, dass wenn Ihr Dateiname von der Form wäre,
./somefile.tar.gz
dannecho ${FILENAME%%.*}
gierig die längste Übereinstimmung mit dem entfernt würde.
und Sie die leere Zeichenfolge hätten.(Sie können dies mit einer temporären Variablen umgehen:
)
Diese Seite erklärt mehr.
quelle
cut
es nicht gibt--complement
undsed
nicht gibt-r
.Das scheint nicht zu funktionieren, wenn die Datei keine Erweiterung oder keinen Dateinamen hat. Hier ist was ich benutze; Es werden nur integrierte Funktionen verwendet und mehr (aber nicht alle) pathologische Dateinamen verarbeitet.
Und hier sind einige Testfälle:
quelle
dir="${fullpath:0:${#fullpath} - ${#filename}}"
habe ich oft gesehendir="${fullpath%$filename}"
. Es ist einfacher zu schreiben. Ich bin mir nicht sicher, ob es einen echten Geschwindigkeitsunterschied oder Fallstricke gibt.which bash
->/bin/bash
; Vielleicht ist es deine Distribution?Sie können verwenden
basename
.Beispiel:
Sie müssen Basisnamen mit der Erweiterung schaffen, der jedoch entfernt werden soll, wenn Sie immer die Ausführung
tar
mit-z
dann wissen Sie , die Erweiterung sein wird.tar.gz
.Dies sollte tun, was Sie wollen:
quelle
cd $(basename $1 .tar.gz)
funktioniert für .gz-Dateien. Aber in Frage erwähnte erArchive files have several extensions: tar.gz, tat.xz, tar.bz2
funktioniert gut, so können Sie einfach verwenden:
Die Befehle funktionieren übrigens wie folgt.
Der Befehl zum
NAME
Ersetzen eines"."
Zeichens, gefolgt von einer beliebigen Anzahl von Nicht-"."
Zeichen bis zum Ende der Zeile, mit nichts (dh er entfernt alles vom Finale"."
bis zum Ende der Zeile, einschließlich). Dies ist im Grunde eine nicht gierige Substitution mit Regex-Tricks.Der Befehl zum
EXTENSION
Ersetzen einer beliebigen Anzahl von Zeichen, gefolgt von einem"."
Zeichen am Zeilenanfang, durch nichts (dh er entfernt alles vom Zeilenanfang bis einschließlich zum letzten Punkt). Dies ist eine gierige Ersetzung, die die Standardaktion ist.quelle
sed 's,\.[^\.]*$,,'
für Name undsed 's,.*\.,., ;t ;g'
Erweiterung (verwendet die atypischentest
undget
Befehle zusammen mit dem typischensubstitute
Befehl).Mellen schreibt in einem Kommentar zu einem Blogbeitrag:
Mit Bash können Sie auch
${file%.*}
den Dateinamen ohne die Erweiterung abrufen und${file##*.}
die Erweiterung alleine abrufen. Das ist,Ausgänge:
quelle
Keine Notwendigkeit, sich mit
awk
odersed
oder sogarperl
für diese einfache Aufgabe zu beschäftigen. Es gibt eine reine Bash-os.path.splitext()
kompatible Lösung, die nur Parametererweiterungen verwendet.Referenzimplementierung
Dokumentation von
os.path.splitext(path)
:Python-Code:
Bash-Implementierung
Führende Perioden ehren
Vorlaufzeiten ignorieren
Tests
Hier sind Testfälle für die Implementierung " Ignorieren führender Perioden" , die bei jeder Eingabe mit der Python-Referenzimplementierung übereinstimmen sollten.
Testergebnisse
Alle Tests bestanden.
quelle
text.tar.gz
solltetext
und die Erweiterung sein.tar.gz
os.path.splitext
in Python. Ob diese Implementierung für möglicherweise kontroverse Eingaben sinnvoll ist, ist ein weiteres Thema."$root"
)? Was könnte passieren, wenn sie weggelassen würden? (Ich konnte keine Dokumentation zu diesem Thema finden.) Wie wird auch mit Dateinamen mit*
oder?
in ihnen umgegangen ?*
und?
nichts Besonderes sind. Die beiden Teile meiner Frage beantworten sich also gegenseitig. Stimmt es, dass dies nicht dokumentiert ist? Oder soll dies aus der Tatsache verstanden werden, dass Zitate die Glob-Expansion im Allgemeinen deaktivieren?root="${path#?}";root="${path::1}${root%.*}"
- Fahren Sie dann mit dem gleichen Verfahren fort, um die Erweiterung zu extrahieren.Mit dem
cut
Befehl können Sie die letzten beiden Erweiterungen (das".tar.gz"
Teil) entfernen :Wie von Clayton Hughes in einem Kommentar bemerkt, funktioniert dies für das tatsächliche Beispiel in der Frage nicht. Als Alternative schlage ich vor,
sed
mit erweiterten regulären Ausdrücken wie folgt zu verwenden:Es funktioniert, indem die letzten beiden (alphanumerischen) Erweiterungen bedingungslos entfernt werden.
[Nach Kommentar von Anders Lindahl erneut aktualisiert]
quelle
$
, um zu überprüfen, ob sich die übereinstimmende Erweiterung am Ende des Dateinamens befindet. Andernfalls kann ein Dateiname wie zu einemi.like.tar.gz.files.tar.bz2
unerwarteten Ergebnis führen.sed
Kettenreihenfolge ist. Auch mit$
am Ende ein Dateiname wiempc-1.0.1.tar.bz2.tar.gz
wird beide.tar.gz
und dann entfernen.tar.bz2
.Hier sind einige alternative Vorschläge (meistens in
awk
), einschließlich einiger fortgeschrittener Anwendungsfälle, wie das Extrahieren von Versionsnummern für Softwarepakete.Alle Anwendungsfälle verwenden den ursprünglichen vollständigen Pfad als Eingabe, ohne von Zwischenergebnissen abhängig zu sein.
quelle
Die akzeptierte Antwort funktioniert gut in typischen Fällen , aber nicht in Rand Fällen , nämlich:
extension=${filename##*.}
den Eingabedateinamen anstelle einer leeren Zeichenfolge zurück.extension=${filename##*.}
enthält nicht die Initiale.
, entgegen der Konvention..
würde für Dateinamen ohne Suffix nicht funktionieren.filename="${filename%.*}"
wird die leere Zeichenfolge sein, wenn der Name der Eingabedatei mit beginnt.
und keine weiteren.
Zeichen enthält (z. B..bash_profile
) - entgegen der Konvention.---------
Die Komplexität einer robusten Lösung, die alle Randfälle abdeckt, erfordert daher eine Funktion - siehe Definition unten; Es kann alle Komponenten eines Pfades zurückgeben .
Beispielaufruf:
Man beachte , dass die Argumente , die nach dem Eingangsweg frei gewählt werden, Positionsvariablennamen .
Um Variablen zu überspringen, die nicht von Interesse sind und vor denen stehen, geben Sie Folgendes an
_
(um die Wegwerfvariable zu verwenden$_
) oder''
; Verwenden Sie zsplitPath '/etc/bash.bashrc' _ _ fnameroot extension
. B. nur den Dateinamen root und die Erweiterung .Testcode, der die Funktion ausübt:
Erwartete Ausgabe - beachten Sie die Randfälle:
.
(gilt nicht als Beginn des Suffixes)/
(Trailing/
wird ignoriert).
wird als übergeordneter Pfad zurückgegeben)..
vorfixierten Token (nur der letzte wird als Suffix betrachtet):quelle
Die kleinste und einfachste Lösung (in einer Zeile) ist:
quelle
echo
. Im Allgemeinenecho $(command)
ist es besser, einfach zu schreiben, escommand
sei denn, Sie fordern die Shell ausdrücklich auf,command
vor der Anzeige des Ergebnisses eine Whitespace-Tokenisierung und eine Platzhaltererweiterung für die Ausgabe durchzuführen . Quiz: Was ist die Ausgabe vonecho $(echo '*')
(und wenn es das ist, was Sie wirklich wollen, wollen Sie wirklich wirklich nurecho *
).echo
Befehl verwendet. Ich habe es nur verwendet, um das Ergebnis zu demonstrieren, dasfoo
in der 3. Zeile als Ergebnis der 2. Zeile erscheint.basename "${file%.*}"
würde einfach das gleiche tun; Sie verwenden eine Befehlsersetzung, um die Ausgabe zu erfassen, und zwar nur fürecho
dieselbe Ausgabe. (Ohne Zitat ist das Ergebnis nominell anders; aber das ist hier kaum relevant,basename "$file" .txt
vermeidet die Komplexität des Parameters Substitution.Ich denke, wenn Sie nur den Namen der Datei benötigen, können Sie dies versuchen:
Und das ist alles = D.
quelle
Sie können das Ausschneiden erzwingen, um alle Felder und nachfolgende Felder anzuzeigen, die
-
zur Feldnummer hinzugefügt werden .Wenn also DATEI ist
eth0.pcap.gz
, wird die ERWEITERUNG seinpcap.gz
Mit der gleichen Logik können Sie den Dateinamen auch mit '-' mit dem folgenden Schnitt abrufen:
Dies funktioniert auch für Dateinamen, die keine Erweiterung haben.
quelle
Magische Dateierkennung
Zusätzlich zu den vielen guten Antworten auf diese Frage zum Stapelüberlauf möchte ich hinzufügen:
Unter Linux und anderen Unixen gibt es einen magischen Befehl namens
file
, der die Dateityperkennung durch Analyse einiger erster Dateibytes durchführt. Dies ist ein sehr altes Tool, das ursprünglich für Druckserver verwendet wurde (wenn es nicht für ... erstellt wurde, da bin ich mir nicht sicher).Standarderweiterungen finden Sie in
/etc/mime.types
(auf meinem Debian GNU / Linux-Desktop. Sieheman file
undman mime.types
. Möglicherweise müssen Sie dasfile
Dienstprogramm und diemime-support
Pakete installieren ):Sie könnten eine erstellen BashFunktion zur Bestimmung der rechten Verlängerung. Es gibt eine kleine (nicht perfekte) Probe:
Diese Funktion kann eine Bash-Variable festlegen, die später verwendet werden kann:
(Dies ist inspiriert von der richtigen Antwort von @Petesh):
quelle
Ok, wenn ich das richtig verstehe, besteht das Problem hier darin, wie man den Namen und die vollständige Erweiterung einer Datei erhält, die mehrere Erweiterungen hat, z
stuff.tar.gz
.Das funktioniert bei mir:
Dies gibt Ihnen
stuff
als Dateinamen und.tar.gz
als Erweiterung. Es funktioniert für eine beliebige Anzahl von Erweiterungen, einschließlich 0. Ich hoffe, dies hilft allen, die das gleiche Problem haben =)quelle
os.path.splitext
, was das OP will) ist('stuff.tar', '.gz')
.Ich benutze das folgende Skript
quelle
Dies ermöglicht mehrere Punkte und Leerzeichen in einem Dateinamen. Wenn jedoch keine Erweiterung vorhanden ist, wird der Dateiname selbst zurückgegeben. Leicht zu überprüfen; Testen Sie einfach, ob Dateiname und Erweiterung identisch sind.
Natürlich funktioniert diese Methode nicht für .tar.gz-Dateien. Dies könnte jedoch in einem zweistufigen Prozess erledigt werden. Wenn die Erweiterung gz ist, überprüfen Sie erneut, ob es auch eine Teererweiterung gibt.
quelle
So extrahieren Sie den Dateinamen und die Erweiterung in Fischen :
Vorsichtsmaßnahmen: Teilung des letzten Punkts, was für Dateinamen mit Punkten gut geeignet ist, für Erweiterungen mit Punkten jedoch nicht. Siehe Beispiel unten.
Verwendungszweck:
Es gibt wahrscheinlich bessere Möglichkeiten, dies zu tun. Fühlen Sie sich frei, meine Antwort zu bearbeiten, um sie zu verbessern.
Wenn es eine begrenzte Anzahl von Erweiterungen gibt, mit denen Sie sich befassen, und Sie alle kennen, versuchen Sie Folgendes:
Dies hat nicht die Einschränkung als erstes Beispiel, aber Sie müssen jeden Fall behandeln, damit es je nach der Anzahl der zu erwartenden Erweiterungen langwieriger werden kann.
quelle
Hier ist Code mit AWK . Es kann einfacher gemacht werden. Aber ich bin nicht gut in AWK.
quelle
split()
.awk -F / '{ n=split($2, a, "."); print a[n] }' uses
/ `als Trennzeichen der obersten Ebene, teilt dann aber die zweiten Felder auf.
und druckt das letzte Element aus dem neuen Array.Einfach benutzen
${parameter%word}
In Ihrem Fall:
Wenn Sie es testen möchten, funktionieren alle folgenden Schritte und entfernen Sie einfach die Erweiterung:
quelle
=
Schilder geben sollte.Aufbauend auf der Antwort von Petesh können , wenn nur der Dateiname benötigt wird, sowohl Pfad als auch Erweiterung in einer einzigen Zeile entfernt werden.
quelle
filename="$(basename "${fullname%.*}")"
basename
ist optional, gibt jedoch die zu entfernende Erweiterung an. Die Substitution ist möglicherweise immer noch nützlich, ist es aber möglicherweisebasename
nicht, da Sie alle diese Substitutionen mit Shell-Builtins durchführen können.Basierend auf @ mklement0s exzellenten und voller zufälliger, nützlicher Bashismen - sowie anderen Antworten auf diese / andere Fragen / "das verdammte Internet" ... habe ich alles in ein wenig, etwas verständlicherem, zusammengefasst. wiederverwendbare Funktion für meine (oder Ihre)
.bash_profile
, die sich darum kümmert, was (ich denke) eine robustere Version vondirname
/basename
/ was Sie haben sollte ..Anwendungsbeispiele ...
quelle
$IFS
(und wenn ja, könnten Sielocal
den Effekt der Einstellung lokalisieren). - Besserlocal
Variablen verwenden. - Ihre Fehlermeldung solltestderr
nicht anstdout
(use1>&2
) ausgegeben werden , und Sie sollten einen Exit-Code ungleich Null zurückgeben. - Besser umbenennenfullname
inbasename
(ersteres schlägt einen Pfad mit dir-Komponenten vor). -name
fügt bedingungslos einen.
(Punkt) hinzu, auch wenn das Original keinen hatte. Sie können dasbasename
Dienstprogramm einfach verwenden , beachten Sie jedoch, dass eine Beendigung ignoriert wird/
.Eine einfache Antwort:
Beachten Sie, dass Sie interessantere Muster erstellen können, um die Antwort auf die POSIX-Variablen zu erweitern . Für den hier beschriebenen Fall können Sie also einfach Folgendes tun:
Dadurch wird das letzte Auftreten von .tar abgeschnitten. <etwas> .
Allgemeiner, wenn Sie das letzte Vorkommen von entfernen möchten. <etwas> . <something-else> dann
sollte gut funktionieren.
Der Link der obigen Antwort scheint tot zu sein. Hier finden Sie eine gute Erklärung für eine Reihe von Zeichenfolgenmanipulationen, die Sie direkt in Bash über TLDP ausführen können .
quelle
Wenn Sie auch leere Erweiterungen zulassen möchten , ist dies die kürzeste, die ich mir vorstellen kann:
1. Zeile erklärt: Es stimmt mit PATH.EXT oder ANYTHING überein und ersetzt es durch EXT. Wenn ALLES übereinstimmt, wird die ext-Gruppe nicht erfasst.
quelle
Dies ist der einzige, der für mich funktioniert hat:
Dies kann auch bei der String-Interpolation verwendet werden, muss aber leider
base
vorher eingestellt werden.quelle
Hier ist der Algorithmus, mit dem ich den Namen und die Erweiterung einer Datei gefunden habe, als ich ein Bash-Skript geschrieben habe, um Namen eindeutig zu machen, wenn Namen in Bezug auf das Gehäuse in Konflikt stehen.
Der Testlauf.
Zu Ihrer Information: Das vollständige Transliterationsprogramm und weitere Testfälle finden Sie hier: https://www.dropbox.com/s/4c6m0f2e28a1vxf/avoid-clashes-code.zip?dl=0
quelle
extension=$([[ "$theFileName" == *.* ]] && echo ".${theFileName##*.}" || echo '')
Verwenden Sie die Beispieldatei
/Users/Jonathan/Scripts/bash/MyScript.sh
, diesen Code:wird zu
${ME}
SeinMyScript
und${MY_EXT}
Sein führen.sh
:Skript:
Einige Tests:
quelle
basename
ist möglicherweise übertrieben.Aus den obigen Antworten ergibt sich der kürzeste Oneliner, der Pythons nachahmt
Angenommen, Ihre Datei hat wirklich eine Erweiterung
quelle
EXT
damit es sich um Schildkröten handelt. (Außerdem sollten Sie alle Großbuchstaben für Ihre privaten Variablennamen vermeiden; sie sind für Systemvariablen reserviert.)