Saisir lextension dans un nom de fichier

Comment obtenir lextension de fichier de bash? Voici ce que jai essayé:

filename=`basename $filepath` fileext=${filename##*.} 

En faisant cela, je peux obtenir lextension de bz2 à partir du chemin /dir/subdir/file.bz2, mais jai un problème avec le chemin /dir/subdir/file-1.0.tar.bz2.

Je préférerais une solution utilisant uniquement bash sans externe programmes si cest possible.

Pour clarifier ma question, je créais un script bash pour extraire une archive donnée juste par une seule commande de extract path_to_file. Comment pour extraire le fichier est déterminé par le script en voyant son type de compression ou darchivage, cela pourrait être .tar.gz, .gz, .bz2 etc. Je pense que cela devrait impliquer une manipulation de chaîne, par exemple si jobtiens lextension .gz alors je devrais vérifier sil a la chaîne .tar avant .gz – si tel est le cas, lextension devrait be .tar.gz.

Commentaires

  • file =  » /dir/subdir/file-1.0.tar.bz2

; echo $ {file ## *.} imprime ‘ .bz2 ‘ ici. Quelle est la sortie que vous ‘ attendez?

  • Jai besoin .tar.bz2
  • Associé : Extraire le nom de fichier et lextension en bash .
  • Réponse

    Si le nom du fichier est file-1.0.tar.bz2, lextension est bz2. La méthode que vous utilisez pour extraire lextension (fileext=${filename##*.}) est parfaitement valide¹.

    Comment décidez-vous que vous voulez que lextension soit tar.bz2 et non bz2 ou 0.tar.bz2? Vous devez dabord répondre à cette question. Ensuite, vous pourrez déterminer ce La commande shell correspond à votre spécification.

    • Une spécification possible est que les extensions doivent commencer par une lettre. Cette heuristique échoue pour quelques extensions courantes comme 7z, ce qui pourrait être mieux traité comme un cas spécial. Ici « implémentation de sa bash / ksh / zsh:

      basename=$filename; fileext= while [[ $basename = ?*.* && ( ${basename##*.} = [A-Za-z]* || ${basename##*.} = 7z ) ]] do fileext=${basename##*.}.$fileext basename=${basename%.*} done fileext=${fileext%.} 

      Pour la portabilité POSIX, vous devez une instruction case pour la correspondance de modèles.

      while case $basename in ?*.*) case ${basename##*.} in [A-Za-z]*|7z) true;; *) false;; esac;; *) false;; esac do … 
    • Une autre spécification possible est que certains les extensions désignent des codages et indiquent quun retrait supplémentaire est nécessaire. Voici « sa mise en œuvre bash / ksh / zsh (nécessitant shopt -s extglob sous bash et setopt ksh_glob sous 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%.} 

      Notez que cela considère 0 comme une extension dans file-1.0.gz.

    ¹ ${VARIABLE##SUFFIX} et les constructions associées sont dans POSIX , donc ils fonctionnent dans nimporte quel shell de style Bourne non ancien tel que ash, bash, ksh ou zsh.

    Commentaires

    • qui devraient être résolu, en vérifiant si la chaîne avant le dernier jeton . est de type archive, par exemple tar, si ce nest pas un type darchive comme 0 litération devrait se terminer.
    • @uray: cela fonctionne dans ce cas particulier, mais ce ‘ nest pas une solution générale . Prenons lexemple de Maciej ‘ de .patch.lzma . Une meilleure heur istic serait de considérer la chaîne après le dernier .: si ‘ est un suffixe de compression (.7z, .bz2, .gz, …), continuez le décapage.
    • @NoamM Quel était le problème avec lindentation? Il ‘ est définitivement cassé après votre modification: le code doublement imbriqué est indenté de la même façon que celui imbriqué individuellement.

    Réponse

    Vous pouvez simplifier les choses en effectuant simplement une recherche de motifs sur le nom de fichier plutôt que dextraire lextension deux fois:

    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 

    Commentaires

    • Cette solution est magnifiquement simple.

    Réponse

    $ echo "thisfile.txt"|awk -F . "{print $NF}" 

    Commentaires à ce sujet ici: http://liquidat.wordpress.com/2007/09/29/short-tip-get-file-extension-in-shell-script/

    Commentaires

    • ne fonctionne pas pour .tar.gz extension
    • Eh bien, un .tar .gz est en fait un tar dans un fichier gzip, donc cela fonctionne dans le sens où il supprime une extension gz dun fichier gzip.

    Réponse

    Voici ma chance: Traduire les points en nouvelles lignes, passer par tail, récupère la dernière ligne:

    $> TEXT=123.234.345.456.456.567.678 $> echo $TEXT | tr . \\n | tail -n1 678 

    Réponse

    Un jour, jai créé ces fonctions délicates:

    # args: string how_many function get_last_letters(){ echo ${1:${#1}-$2:$2}; } function cut_last_letters(){ echo ${1:0:${#1}-$2}; } 

    Jai trouvé cette approche simple, très utile dans de nombreux cas, pas seulement quand elle va à propos des extensions.

    Pour vérifier les extensions – Cest simple et fiable

    ~$ get_last_letters file.bz2 4 .bz2 ~$ get_last_letters file.0.tar.bz2 4 .bz2 

    Pour couper lextension:

    ~$ cut_last_letters file.0.tar.bz2 4 file.0.tar 

    Pour changer lextension:

    ~$ echo $(cut_last_letters file.0.tar.bz2 4).gz file.0.tar.gz 

    Ou, si vous aimez les « fonctions pratiques:

    ~$ 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 Si vous avez aimé ces fonctions ou les avez trouvées utilisées pleinement, sil vous plaît se référer à ce post 🙂 (et nous espérons mettre un commentaire).

    Réponse

    echo ${filename#$(echo $filename | sed "s/\.[^[:digit:]].*$//g;")} 

    Par exemple:

    Commentaires

    • Ne fonctionne pas dans tous les cas. Essayez avec ‘ foo.7z ‘
    • Vous avez besoin de guillemets et mieux vaut utiliser printf si le nom du fichier contient une barre oblique inverse ou commence par -: "${filename#$(printf %s "$filename" | sed 's/\.[^[:digit:]].*$//g;')}"
    • @axel_c : right, et jai ‘ implémenté la même spécification que Maciej à titre dexemple. Quelle heuristique suggérez-vous que ‘ est meilleure que « commence par une lettre »?
    • @Gilles: jy pense simplement ‘ nest pas une solution, sauf si vous utilisez une liste précalculée dextensions connues, car une extension peut être nimporte quoi.

    Réponse

    la réponse basée sur la casse jackman est assez bonne et portable, mais si vous voulez juste le nom de fichier et lextension dans une variable, jai trouvé cette solution:

    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 

    Cela ne fonctionne quavec des extensions doubles et la première doit être « tar ».

    Mais vous pouvez changer la ligne de test « tar » avec un test de longueur de chaîne et répéter le correctif plusieurs fois .

    Réponse

    Je lai résolu en utilisant ceci:

    filename=`basename $filepath` fileext=${filename##*.} fileext2=${filename%.*} fileext3=${fileext2##*.} if [ "$fileext3" == "tar" ]; then fileext="tar."$fileext fi 

    mais cela ne fonctionne que pour le type darchivage connu, dans ce cas uniquement tar

    Laisser un commentaire

    Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *