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?
.tar.bz2
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 etsetopt 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 dansfile-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 exempletar
, si ce nest pas un type darchive comme0
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