Prendendo lestensione in un nome di file

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?

  • ho bisogno di .tar.bz2
  • Correlato : Estrai nome file ed estensione in Bash .
  • 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 e setopt 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 in file-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 esempio tar, se non è di tipo archivio come 0 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

    Lascia un commento

    Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *