Cum obțin extensia de fișier din bash? Iată ce am încercat:
filename=`basename $filepath` fileext=${filename##*.}
Procedând astfel pot obține extensia bz2
din calea /dir/subdir/file.bz2
, dar am o problemă cu calea /dir/subdir/file-1.0.tar.bz2
.
Aș prefera o soluție folosind doar bash fără extern programe dacă este posibil.
Pentru a clarifica întrebarea, am creat un script bash pentru a extrage orice arhivă dată doar printr-o singură comandă a extract path_to_file
. Cum extragerea fișierului este determinată de script, văzând tipul de compresie sau arhivare a acestuia, care ar putea fi .tar.gz, .gz, .bz2 etc. Cred că acest lucru ar trebui să implice manipularea șirurilor, de exemplu dacă primesc extensia .gz
atunci ar trebui să verific dacă are șirul .tar
înainte de .gz
– dacă da, extensia ar trebui fi .tar.gz
.
Comentarii
- file = ” /dir/subdir/file-1.0.tar.bz2
; echo $ {file ## *.} imprimă aici ‘ .bz2 ‘ Care este rezultatul pe care ‘ îl așteptați?
.tar.bz2
Răspuns
Dacă numele fișierului este file-1.0.tar.bz2
, extensia este bz2
. Metoda pe care o utilizați pentru a extrage extensia (fileext=${filename##*.}
) este perfect valabilă¹.
Cum decideți că doriți ca extensia să fie tar.bz2
și nu bz2
sau 0.tar.bz2
? Mai întâi trebuie să răspundeți la această întrebare. Apoi puteți afla ce comanda shell se potrivește cu specificația dvs.
-
O posibilă specificație este că extensiile trebuie să înceapă cu o literă. Această euristică eșuează pentru câteva extensii comune, cum ar fi
7z
, care ar putea fi tratat cel mai bine ca un caz special. Aici „implementarea sa bash / ksh / zsh:basename=$filename; fileext= while [[ $basename = ?*.* && ( ${basename##*.} = [A-Za-z]* || ${basename##*.} = 7z ) ]] do fileext=${basename##*.}.$fileext basename=${basename%.*} done fileext=${fileext%.}
Pentru portabilitatea POSIX, trebuie să utilizați o instrucțiune
case
pentru potrivirea modelelor.while case $basename in ?*.*) case ${basename##*.} in [A-Za-z]*|7z) true;; *) false;; esac;; *) false;; esac do …
-
O altă posibilă specificație este că unele extensiile denotă codificări și indică faptul că este necesară o stripare suplimentară. Aici „implementarea sa bash / ksh / zsh (necesită
shopt -s extglob
sub bash șisetopt ksh_glob
sub 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%.}
Rețineți că acest lucru consideră
0
o extensie înfile-1.0.gz
.
¹ ${VARIABLE##SUFFIX}
și construcțiile aferente sunt în POSIX , deci funcționează în orice coajă în stil Bourne care nu este antică, cum ar fi ash, bash, ksh sau zsh.
Comentarii
- care ar trebui să fie rezolvat, verificând dacă șirul dinaintea ultimului simbol
.
este tip arhivă, de exemplutar
, dacă nu este tip arhivă ca0
iterația ar trebui să se încheie. - @uray: funcționează în acest caz particular, dar ‘ nu este o soluție generală . Luați în considerare Maciej ‘ exemplu de
.patch.lzma
. Un heur mai bun istic ar fi să ia în considerare șirul după ultimul.
: dacă este ‘ un sufix de compresie (.7z
,.bz2
,.gz
, …), continuați dezlipirea. - @NoamM Ce a fost în neregulă cu indentarea? ‘ este cu siguranță rupt după editarea dvs.: codul dublu imbricat este indentat la fel ca cel cuplat individual.
Răspundeți
S-ar putea să simplificați lucrurile făcând doar potrivirea de tipare pe numele fișierului, decât să extrageți extensia de două ori:
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
Comentarii
- Această soluție este foarte simplă.
Răspuns
$ echo "thisfile.txt"|awk -F . "{print $NF}"
Comentarii aici: http://liquidat.wordpress.com/2007/09/29/short-tip-get-file-extension-in-shell-script/
Comentarii
- nu funcționează pentru extensia
.tar.gz
- Ei bine, o .tar .gz este de fapt un tar în interiorul unui fișier gzip, deci funcționează în sensul că elimină o extensie gz dintr-un fișier gzip.
Răspuns
Iată ce am făcut: traduceți punctele în linii noi, treceți prin tail
, obțineți ultima linie:
$> TEXT=123.234.345.456.456.567.678 $> echo $TEXT | tr . \\n | tail -n1 678
Răspuns
Într-o zi, am „creat acele funcții complicate:
# args: string how_many function get_last_letters(){ echo ${1:${#1}-$2:$2}; } function cut_last_letters(){ echo ${1:0:${#1}-$2}; }
Am găsit această abordare simplă, foarte utilă în multe cazuri, nu numai când merge despre extensii.
Pentru verificarea extensiilor – Este simplu și fiabil
~$ get_last_letters file.bz2 4 .bz2 ~$ get_last_letters file.0.tar.bz2 4 .bz2
Pentru extensia de tăiere:
~$ cut_last_letters file.0.tar.bz2 4 file.0.tar
Pentru schimbarea extensiei:
~$ echo $(cut_last_letters file.0.tar.bz2 4).gz file.0.tar.gz
Sau, dacă vă plac „funcțiile la îndemână:
~$ 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 Dacă v-au plăcut aceste funcții sau le-ați găsit folosite, vă rugăm să consultați această postare 🙂 (și, sperăm, puneți un comentariu).
Răspuns
echo ${filename#$(echo $filename | sed "s/\.[^[:digit:]].*$//g;")}
De exemplu:
Comentarii
- Nu funcționează pentru toate cazurile. Încercați cu ‘ foo.7z ‘
- Aveți nevoie de ghilimele și utilizați mai bine
printf
în cazul în care numele fișierului conține o bară inversă sau începe cu-
:"${filename#$(printf %s "$filename" | sed 's/\.[^[:digit:]].*$//g;')}"
- @axel_c : dreapta și am ‘ am implementat aceeași specificație ca Maciej ca exemplu. Ce euristică sugerați că ‘ este mai bun decât „începe cu o literă”?
- @Gilles: Cred că există ‘ nu este o soluție decât dacă utilizați o listă precomputată de extensii cunoscute, deoarece o extensie poate fi orice.
Răspuns
răspunsul bazat pe cazurile jackman este destul de bun și portabil, dar dacă doriți doar numele fișierului și extensia într-o variabilă, am găsit această soluție:
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
Funcționează numai cu extensii duble, iar prima trebuie să fie „tar”.
Dar puteți schimba linia de test „tar” cu un test de lungime a șirului și repetați remedierea de mai multe ori .
Răspuns
Am rezolvat-o folosind acest lucru:
filename=`basename $filepath` fileext=${filename##*.} fileext2=${filename%.*} fileext3=${fileext2##*.} if [ "$fileext3" == "tar" ]; then fileext="tar."$fileext fi
dar acest lucru funcționează numai pentru tipul de arhivare cunoscut, în acest caz numai tar