Come ottengo lestensione di file da bash? Ecco cosa ho provato:
filename=`basename $filepath` fileext=${filename##*.}
In questo modo posso ottenere lestensione di bz2
dal percorso /dir/subdir/file.bz2
, ma ho un problema con il percorso /dir/subdir/file-1.0.tar.bz2
.
Preferirei una soluzione utilizzando solo bash senza esterno programmi se è possibile.
Per rendere chiara la mia domanda, stavo creando uno script bash per estrarre un dato archivio solo con un singolo comando di extract path_to_file
. Come per estrarre il file è determinato dallo script vedendo il suo tipo di compressione o archiviazione, che potrebbe essere .tar.gz, .gz, .bz2 ecc. Penso che questo dovrebbe comportare la manipolazione delle stringhe, ad esempio se ottengo lestensione .gz
, dovrei controllare se ha la stringa .tar
prima di .gz
– in tal caso, lestensione dovrebbe essere .tar.gz
.
Commenti
- file = ” /dir/subdir/file-1.0.tar.bz2
; echo $ {file ## *.} stampa ‘ .bz2 ‘ qui. Qual è loutput che ‘ ti aspetti?
.tar.bz2
Risposta
Se il nome del file è file-1.0.tar.bz2
, lestensione è bz2
. Il metodo che stai utilizzando per estrarre lestensione (fileext=${filename##*.}
) è perfettamente valido¹.
Come decidi che vuoi che lestensione sia tar.bz2
e non bz2
o 0.tar.bz2
? Devi prima rispondere a questa domanda. Quindi puoi capire cosa Il comando shell corrisponde alla tua specifica.
-
Una possibile specifica è che le estensioni devono iniziare con una lettera. Questa euristica non riesce per alcune estensioni comuni come
7z
, che potrebbe essere trattato al meglio come un caso speciale. Qui “unimplementazione di bash / ksh / zsh:basename=$filename; fileext= while [[ $basename = ?*.* && ( ${basename##*.} = [A-Za-z]* || ${basename##*.} = 7z ) ]] do fileext=${basename##*.}.$fileext basename=${basename%.*} done fileext=${fileext%.}
Per la portabilità POSIX, è necessario utilizzare unistruzione
case
per la corrispondenza dei modelli.while case $basename in ?*.*) case ${basename##*.} in [A-Za-z]*|7z) true;; *) false;; esac;; *) false;; esac do …
-
Unaltra possibile specifica è che alcuni estensioni denotano codifiche e indicano che è necessaria unulteriore eliminazione. Ecco limplementazione di “sa bash / ksh / zsh (che richiede
shopt -s extglob
in bash esetopt ksh_glob
in 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%.}
Tieni presente che questo considera
0
unestensione infile-1.0.gz
.
¹ ${VARIABLE##SUFFIX}
e i relativi costrutti si trovano in POSIX , quindi funzionano in qualsiasi shell non antica in stile Bourne come ash, bash, ksh o zsh.
Commenti
- che dovrebbe essere risolto controllando se la stringa prima dellultimo
.
token è di tipo archivio, ad esempiotar
, se non è di tipo archivio come0
literazione dovrebbe terminare. - @uray: funziona in questo caso particolare, ma ‘ non è una soluzione generale . Considera Maciej ‘ s esempio di
.patch.lzma
. Un heur migliore istic sarebbe considerare la stringa dopo lultimo.
: se ‘ sa suffisso di compressione (.7z
,.bz2
,.gz
, …), continua a rimuovere. - @NoamM Cosa cera di sbagliato nel rientro? ‘ è definitivamente interrotto dopo la tua modifica: il codice doppiamente annidato ha lo stesso rientro di quello annidato singolarmente.
Risposta
Potresti semplificare le cose semplicemente eseguendo la corrispondenza del modello sul nome del file anziché estrarre lestensione due volte:
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
Commenti
- Questa soluzione è meravigliosamente semplice.
Risposta
$ echo "thisfile.txt"|awk -F . "{print $NF}"
Commenti su questo qui: http://liquidat.wordpress.com/2007/09/29/short-tip-get-file-extension-in-shell-script/
Commenti
- non funziona per
.tar.gz
estensione - Bene un .tar .gz è in realtà un tar allinterno di un file gzip, quindi funziona nel senso che rimuove unestensione gz da un file gzip.
Risposta
Ecco la mia possibilità: traduci i punti in nuove righe, conduci attraverso tail
, ottieni lultima riga:
$> TEXT=123.234.345.456.456.567.678 $> echo $TEXT | tr . \\n | tail -n1 678
Risposta
Un giorno ho creato quelle funzioni complicate:
# args: string how_many function get_last_letters(){ echo ${1:${#1}-$2:$2}; } function cut_last_letters(){ echo ${1:0:${#1}-$2}; }
Ho trovato questo approccio diretto, molto utile in molti casi, non solo quando va sulle estensioni.
Per controllare le estensioni – È semplice e affidabile
~$ get_last_letters file.bz2 4 .bz2 ~$ get_last_letters file.0.tar.bz2 4 .bz2
Per interrompere lestensione:
~$ cut_last_letters file.0.tar.bz2 4 file.0.tar
Per modificare lestensione:
~$ echo $(cut_last_letters file.0.tar.bz2 4).gz file.0.tar.gz
Oppure, se ti piacciono le “funzioni utili:
~$ 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 Se ti sono piaciute queste funzioni o le hai trovate usate completamente, si prega di fare riferimento a questo post 🙂 (e si spera di inserire un commento).
Risposta
echo ${filename#$(echo $filename | sed "s/\.[^[:digit:]].*$//g;")}
Ad esempio:
Commenti
- Non funziona per tutti i casi. Prova con ‘ foo.7z ‘
- Hai bisogno di virgolette e usa meglio
printf
nel caso in cui il nome del file contenga una barra rovesciata o inizi con-
:"${filename#$(printf %s "$filename" | sed 's/\.[^[:digit:]].*$//g;')}"
- @axel_c : right, e io ‘ ho implementato la stessa specifica di Maciej come esempio. Quale euristica suggerisci che ‘ sia meglio di “inizia con una lettera”?
- @Gilles: ci penso solo ‘ non è una soluzione a meno che non si utilizzi un elenco precalutato di estensioni note, perché unestensione può essere qualsiasi cosa.
Risposta
la risposta basata sui casi di jackman è piuttosto buona e portabile, ma se vuoi solo il nome del file e lestensione in una variabile, ho trovato questa soluzione:
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
Funziona solo con estensioni doppie e la prima deve essere “tar”.
Ma puoi cambiare la riga di test “tar” con un test della lunghezza della stringa e ripetere la correzione più volte .
Risposta
lho risolto usando questo:
filename=`basename $filepath` fileext=${filename##*.} fileext2=${filename%.*} fileext3=${fileext2##*.} if [ "$fileext3" == "tar" ]; then fileext="tar."$fileext fi
ma funziona solo per il tipo di archiviazione noto, in questo caso solo tar