Wie erhalte ich die Dateierweiterung von bash? Folgendes habe ich versucht:
filename=`basename $filepath` fileext=${filename##*.}
Auf diese Weise kann ich die Erweiterung von bz2
vom Pfad /dir/subdir/file.bz2
, aber ich habe ein Problem mit dem Pfad /dir/subdir/file-1.0.tar.bz2
.
Ich würde eine Lösung bevorzugen, die nur bash ohne externes verwendet Programme, wenn es möglich ist.
Um meine Frage klar zu stellen, habe ich ein Bash-Skript erstellt, um ein bestimmtes Archiv nur mit einem einzigen Befehl von extract path_to_file
zu extrahieren Das Extrahieren der Datei wird vom Skript anhand des Komprimierungs- oder Archivierungstyps festgelegt, der .tar.gz, .gz, .bz2 usw. sein kann. Ich denke, dies sollte eine Zeichenfolgenmanipulation beinhalten, beispielsweise wenn ich die Erweiterung .gz
dann sollte ich prüfen, ob die Zeichenfolge .tar
vor .gz
steht – wenn ja, sollte die Erweiterung .tar.gz
.
Kommentare
- file = “ /dir/subdir/file-1.0.tar.bz2
; echo $ {file ## *.} druckt hier ‚ .bz2 ‚. Was ist die Ausgabe, die Sie ‚ erwarten?
.tar.bz2
Antwort
Wenn der Dateiname file-1.0.tar.bz2
lautet, lautet die Erweiterung bz2
. Die Methode, mit der Sie die Erweiterung extrahieren (fileext=${filename##*.}
), ist vollkommen gültig¹.
Wie entscheiden Sie, dass die Erweiterung tar.bz2
und nicht bz2
oder 0.tar.bz2
? Sie müssen diese Frage zuerst beantworten. Dann können Sie herausfinden, was Der Shell-Befehl entspricht Ihrer Spezifikation.
-
Eine mögliche Spezifikation ist, dass Erweiterungen mit einem Buchstaben beginnen müssen. Diese Heuristik schlägt für einige häufig verwendete Erweiterungen wie
7z
, was am besten als Sonderfall behandelt werden kann. Hier „sa bash / ksh / zsh-Implementierung:basename=$filename; fileext= while [[ $basename = ?*.* && ( ${basename##*.} = [A-Za-z]* || ${basename##*.} = 7z ) ]] do fileext=${basename##*.}.$fileext basename=${basename%.*} done fileext=${fileext%.}
Für die POSIX-Portabilität müssen Sie verwenden eine
case
-Anweisung für den Mustervergleich.while case $basename in ?*.*) case ${basename##*.} in [A-Za-z]*|7z) true;; *) false;; esac;; *) false;; esac do …
-
Eine andere mögliche Spezifikation ist, dass einige Erweiterungen bezeichnen Codierungen und zeigen an, dass weiteres Strippen erforderlich ist. Hier „sa bash / ksh / zsh-Implementierung (erfordert
shopt -s extglob
unter bash undsetopt ksh_glob
unter zsh):basename=$filename fileext= while [[ $basename = ?*.@(bz2|gz|lzma) ]]; do fileext=${basename##*.}.$fileext basename=${basename%.*} done if [[ $basename = ?*.* ]]; then fileext=${basename##*.}.$fileext basename=${basename%.*} fi fileext=${fileext%.}
Beachten Sie, dass dies
0
als Erweiterung infile-1.0.gz
betrachtet.
¹ ${VARIABLE##SUFFIX}
und verwandte Konstrukte befinden sich in POSIX Sie funktionieren in jeder nicht antiken Shell im Bourne-Stil wie Asche, Bash, Ksh oder Zsh.
Kommentare
- , die sollten gelöst werden, indem überprüft wird, ob die Zeichenfolge vor dem letzten
.
-Token vom Archivtyp ist, z. B.tar
, wenn es sich nicht um einen Archivtyp wie0
Die Iteration sollte enden. - @uray: Das funktioniert in diesem speziellen Fall, aber ‚ ist keine allgemeine Lösung Betrachten Sie das Beispiel von Maciej ‚ für
.patch.lzma
Es wäre wichtig, die Zeichenfolge nach dem letzten.
zu betrachten: wenn sie ‚ ein Komprimierungssuffix (.7z
,.bz2
,.gz
, …), Strippen Sie weiter. - @NoamM Was war falsch an der Einrückung? ‚ ist nach Ihrer Bearbeitung definitiv fehlerhaft: doppelt verschachtelter Code wird genauso eingerückt wie einfach verschachtelter.
Antwort
Sie können die Sache vereinfachen, indem Sie nur einen Mustervergleich für den Dateinamen durchführen, anstatt die Erweiterung zweimal zu extrahieren:
case "$filename" in *.tar.bz2) bunzip_then_untar ;; *.bz2) bunzip_only ;; *.tar.gz) untar_with -z ;; *.tgz) untar_with -z ;; *.gz) gunzip_only ;; *.zip) unzip ;; *.7z) do something ;; *) do nothing ;; esac
Kommentare
- Diese Lösung ist sehr einfach.
Antwort
$ echo "thisfile.txt"|awk -F . "{print $NF}"
Kommentare hierzu: http://liquidat.wordpress.com/2007/09/29/short-tip-get-file-extension-in-shell-script/
Kommentare
- funktioniert nicht für die
.tar.gz
-Erweiterung - Nun, ein .tar .gz ist eigentlich ein Teer in einer GZIP-Datei, funktioniert also in dem Sinne, dass eine GZ-Erweiterung aus einer GZIP-Datei entfernt wird.
Antwort
Hier ist mein Schuss: Übersetzen Sie Punkte in Zeilenumbrüche, leiten Sie durch tail
, letzte Zeile abrufen:
$> TEXT=123.234.345.456.456.567.678 $> echo $TEXT | tr . \\n | tail -n1 678
Antwort
Eines Tages habe ich diese kniffligen Funktionen erstellt:
# args: string how_many function get_last_letters(){ echo ${1:${#1}-$2:$2}; } function cut_last_letters(){ echo ${1:0:${#1}-$2}; }
Ich habe diesen einfachen Ansatz gefunden, der in vielen Fällen sehr nützlich ist, nicht nur, wenn er funktioniert Informationen zu Erweiterungen.
Zum Überprüfen von Erweiterungen – Es ist einfach und zuverlässig.
~$ get_last_letters file.bz2 4 .bz2 ~$ get_last_letters file.0.tar.bz2 4 .bz2
Zum Abschneiden der Erweiterung:
~$ cut_last_letters file.0.tar.bz2 4 file.0.tar
Zum Ändern der Erweiterung:
~$ echo $(cut_last_letters file.0.tar.bz2 4).gz file.0.tar.gz
Oder, wenn Sie „praktische Funktionen“ mögen:
~$ function cut_last_letters_and_add(){ echo ${1:0:${#1}-$2}"$3"; } ~$ cut_last_letters_and_add file.0.tar.bz2 4 .gz file.0.tar.gz
PS Wenn Ihnen diese Funktionen gefallen haben oder Sie sie als nützlich empfunden haben, Bitte lesen Sie diesen Beitrag 🙂 (und geben Sie hoffentlich einen Kommentar ab).
Antwort
echo ${filename#$(echo $filename | sed "s/\.[^[:digit:]].*$//g;")}
Zum Beispiel:
Kommentare
- Funktioniert nicht in allen Fällen. Versuchen Sie es mit ‚ foo.7z ‚
- Sie benötigen Anführungszeichen und verwenden besser
printf
falls der Dateiname einen Backslash enthält oder mit-
beginnt:"${filename#$(printf %s "$filename" | sed 's/\.[^[:digit:]].*$//g;')}"
- @axel_c : richtig, und ich ‚ habe die gleiche Spezifikation wie Maciej als Beispiel implementiert. Welche Heuristik schlagen Sie vor, dass ‚ besser ist als „beginnt mit einem Buchstaben“?
- @Gilles: Ich denke nur, dass dort ‚ ist keine Lösung, es sei denn, Sie verwenden eine vorberechnete Liste bekannter Erweiterungen, da eine Erweiterung alles sein kann.
Antwort
Die auf Jackman-Groß- und Kleinschreibung basierende Antwort ist ziemlich gut und portabel. Wenn Sie jedoch nur den Dateinamen und die Erweiterung in einer Variablen haben möchten, habe ich diese Lösung gefunden:
INPUTFILE="$1" INPUTFILEEXT=$( echo -n "$INPUTFILE" | rev | cut -d"." -f1 | rev ) INPUTFILEEXT=$( echo -n $INPUTFILEEXT | tr "[A-Z]" "[a-z]" ) # force lowercase extension INPUTFILENAME="`echo -n \"$INPUTFILE\" | rev | cut -d"." -f2- | rev`" # fix for files with multiple extensions like "gbamidi-v1.0.tar.gz" INPUTFILEEXT2=$( echo -n "$INPUTFILENAME" | rev | cut -d"." -f1 | rev ) if [ "$INPUTFILEEXT2" = "tar" ]; then # concatenate the extension INPUTFILEEXT="$INPUTFILEEXT2.$INPUTFILEEXT" # update the filename INPUTFILENAME="`echo -n \"$INPUTFILENAME\" | rev | cut -d"." -f2- | rev`" fi
Es funktioniert nur mit doppelten Erweiterungen und die erste muss „tar“ sein.
Sie können die „tar“ -Testzeile jedoch durch einen Stringlängentest ändern und den Fix mehrmals wiederholen .
Antwort
Ich habe es folgendermaßen gelöst:
filename=`basename $filepath` fileext=${filename##*.} fileext2=${filename%.*} fileext3=${fileext2##*.} if [ "$fileext3" == "tar" ]; then fileext="tar."$fileext fi
Dies funktioniert jedoch nur für bekannte Archivierungstypen, in diesem Fall nur tar