Comment puis-je supprimer le suffixe de fichier et la partie path d'une chaîne de chemin dans Bash?

Étant donné un chemin de fichier de chaîne tel que " / foo / fizzbuzz.bar", comment utiliserais-je bash pour extraire uniquement la partie" fizzbuzz " de ladite chaîne?

321
demandé sur codeforester 2008-09-24 07:37:00

13 réponses

Voici comment le faire avec les opérateurs # et % dans Bash.

$ x="/foo/fizzbuzz.bar"
$ y=${x%.bar}
$ echo ${y##*/}
fizzbuzz

${x%.bar} peut aussi être ${x%.*} pour tout supprimer après un point ou ${x%%.*} pour tout supprimer après le premier point.

Exemple:

$ x="/foo/fizzbuzz.bar.quux"
$ y=${x%.*}
$ echo $y
/foo/fizzbuzz.bar
$ y=${x%%.*}
$ echo $y
/foo/fizzbuzz

La Documentation se trouve dans le manuel Bash . Recherchez ${parameter%word} et ${parameter%%word} section correspondant à la partie de fin.

448
répondu Zan Lynx 2016-10-14 14:36:17

Regardez la commande basename:

NAME=`basename /foo/fizzbuzz.bar .bar`
177
répondu zigdon 2008-09-24 03:38:03

Pur bash, fait en deux opérations distinctes:

  1. Supprime le chemin d'une chaîne de chemin:

    path=/foo/bar/bim/baz/file.gif
    
    file=${path##*/}  
    #$file is now 'file.gif'
    
  2. Supprime l'extension d'une chaîne de chemin:

    base=${file%.*}
    #${base} is now 'file'.
    
30
répondu Param 2014-11-29 17:48:03

En utilisant basename j'ai utilisé ce qui suit pour y parvenir:

for file in *; do
    ext=${file##*.}
    fname=`basename $file $ext`

    # Do things with $fname
done;

Cela ne nécessite aucune connaissance a priori de l'extension de fichier et fonctionne même lorsque vous avez un nom de fichier qui a des points dans son nom de fichier (devant son extension); cela nécessite le programme basename, mais cela fait partie de GNU coreutils, donc il devrait être livré avec n'importe quelle distribution.

13
répondu mike 2014-04-11 17:07:04

Pur Bash façon:

~$ x="/foo/bar/fizzbuzz.bar.quux.zoom"; 
~$ y=${x/\/*\//}; 
~$ echo ${y/.*/}; 
fizzbuzz

Cette fonctionnalité est expliquée sur man bash sous "parameter Expansion". Les moyens non bash abondent: awk, perl, sed et ainsi de suite.

EDIT: fonctionne avec des points dans le fichier suffixes et n'a pas besoin de connaître le suffixe (extension), mais ne fonctionne pas avec des points dans le nom lui-même.

12
répondu Vinko Vrsalovic 2012-09-02 15:59:07

Les fonctions basename et dirname sont ce que vous recherchez:

mystring=/foo/fizzbuzz.bar
echo basename: $(basename $mystring)
echo basename + remove .bar: $(basename $mystring .bar)
echo dirname: $(dirname $mystring)

A la sortie:

basename: fizzbuzz.bar
basename + remove .bar: fizzbuzz
dirname: /foo
7
répondu Jerub 2008-09-24 03:40:06
perl -pe 's/\..*$//;s{^.*/}{}'
3
répondu mopoke 2008-09-24 03:39:34

L'utilisation de basename suppose que vous connaissez l'extension de fichier, n'est-ce pas?

Et je crois que les différentes suggestions d'expressions régulières ne font pas face à un nom de fichier contenant plus d'un "."

Ce qui suit semble faire face à des points doubles. Oh, et les noms de fichiers qui contiennent un " / " eux-mêmes (juste pour les coups de pied)

Pour paraphraser Pascal, " Désolé ce script est si long. Je n'ai pas eu le temps de le raccourcir "


  #!/usr/bin/perl
  $fullname = $ARGV[0];
  ($path,$name) = $fullname =~ /^(.*[^\\]\/)*(.*)$/;
  ($basename,$extension) = $name =~ /^(.*)(\.[^.]*)$/;
  print $basename . "\n";
 
3
répondu Andrew Edgecombe 2008-09-24 05:07:37

Si vous ne pouvez pas utiliser basename comme suggéré dans d'autres publications, vous pouvez toujours utiliser sed. Voici un (vilain) exemple. Ce n'est pas le plus grand, mais cela fonctionne en extrayant la chaîne désirée et en remplaçant l'entrée par la chaîne désirée.

echo '/foo/fizzbuzz.bar' | sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'

Qui vous donnera la sortie

Fizzbuzz

2
répondu nymacro 2008-09-24 11:12:06

Méfiez-vous de la solution Perl suggérée: elle supprime n'importe quoi après le premier point.

$ echo some.file.with.dots | perl -pe 's/\..*$//;s{^.*/}{}'
some

Si vous voulez le faire avec perl, cela fonctionne:

$ echo some.file.with.dots | perl -pe 's/(.*)\..*$/$1/;s{^.*/}{}'
some.file.with

, Mais si vous utilisez Bash, les solutions avec y=${x%.*} (ou basename "$x" .ext si vous connaissez l'extension) sont beaucoup plus simples.

2
répondu mivk 2010-06-19 10:35:04

Combinaison de la réponse la mieux notée avec la deuxième réponse la mieux notée pour obtenir le nom de fichier sans le chemin complet:

$ x="/foo/fizzbuzz.bar.quux"
$ y=(`basename ${x%%.*}`)
$ echo $y
fizzbuzz
1
répondu c.gutierrez 2014-08-20 18:30:44

Le nom de base fait cela, supprime le chemin. Il supprimera également le suffixe s'il est donné et s'il correspond au suffixe du fichier, mais vous devrez connaître le suffixe pour donner à la commande. Sinon, vous pouvez utiliser mv et comprendre ce que le nouveau nom devrait être d'une autre manière.

0
répondu waynecolvin 2008-11-15 00:47:41

Informations que vous pouvez trouver dans Bash manuel, recherchez ${parameter%word} et ${parameter%%word} dans la partie arrière de section de filtre.

0
répondu 1ac0 2016-09-20 11:44:53