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

StackOverflow https://stackoverflow.com/questions/125281

  •  02-07-2019
  •  | 
  •  

Question

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

Était-ce utile?

La solution

Voici comment procéder avec les opérateurs # et% de Bash.

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

$ {x% .bar} peut également ê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 Manuel Bash . Recherchez les sections $ {paramètre% mot} et $ {paramètre %% mot} .

Autres conseils

regardez la commande basename:

NAME=$(basename /foo/fizzbuzz.bar .bar)

Pure bash, effectuée en deux opérations distinctes:

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

    path=/foo/bar/bim/baz/file.gif
    
    file=${path##*/}  
    #$file is now 'file.gif'
    
  2. Supprimer l'extension d'un chemin d'accès:

    base=${file%.*}
    #${base} is now 'file'.
    

À l'aide du nom de base, j'ai utilisé les éléments suivants pour y parvenir:

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

    # Do things with $fname
done;

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

façon pure bash:

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

Cette fonctionnalité est expliquée dans man bash sous "Développement de paramètres". Les moyens non bash abondent: awk, perl, sed et ainsi de suite.

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

Ce que vous recherchez, ce sont les fonctions basename et dirname:

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

a une sortie:

basename: fizzbuzz.bar
basename + remove .bar: fizzbuzz
dirname: /foo
perl -pe 's/\..*$//;s{^.*/}{}'

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

Et je pense que les différentes suggestions d’expression rationnelle ne s’adaptent pas à un nom de fichier contenant plusieurs ".".

Ce qui suit semble faire face à des points doubles. Oh, et les noms de fichiers contenant 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";
 

Si vous ne pouvez pas utiliser le nom de base comme suggéré dans d'autres publications, vous pouvez toujours utiliser sed. Voici un exemple (laid). Ce n'est pas ce qu'il y a de mieux, mais cela fonctionne en extrayant la chaîne souhaitée et en remplaçant l'entrée par la chaîne souhaitée.

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

Ce qui vous donnera la sortie

  
    

fizzbuzz

  

En plus de la syntaxe conforme à POSIX utilisée dans cette réponse ,

basename string [suffix]

comme dans

basename /foo/fizzbuzz.bar .bar

GNU nom de base supporte une autre syntaxe:

basename -s .bar /foo/fizzbuzz.bar

avec le même résultat. La différence et l'avantage est que -s implique -a , qui prend en charge plusieurs arguments:

$ basename -s .bar /foo/fizzbuzz.bar /baz/foobar.bar
fizzbuzz
foobar

Cela peut même être rendu sûr pour le nom de fichier en séparant la sortie avec des octets NUL en utilisant l'option -z , par exemple pour ces fichiers contenant des blancs, des nouvelles lignes et des caractères globaux (cités par ls ):

$ ls has*
'has'

Lecture dans un tableau:

$ readarray -d 

readarray -d nécessite Bash 4.4 ou plus récent. Pour les anciennes versions, nous devons boucler:

while IFS= read -r -d '' fname; do arr+=("$fname"); done < <(basename -zs .bar has*)
\n''newline.bar' 'has space.bar' 'has*.bar'

Lecture dans un tableau:

<*>

readarray -d nécessite Bash 4.4 ou plus récent. Pour les anciennes versions, nous devons boucler:

<*>\0' arr < <(basename -zs .bar has*) $ declare -p arr declare -a arr=([0]=

readarray -d nécessite Bash 4.4 ou plus récent. Pour les anciennes versions, nous devons boucler:

<*>\n''newline.bar' 'has space.bar' 'has*.bar'

Lecture dans un tableau:

<*>

readarray -d nécessite Bash 4.4 ou plus récent. Pour les anciennes versions, nous devons boucler:

<*>has\nnewline' [1]="has space" [2]="has*")

readarray -d nécessite Bash 4.4 ou plus récent. Pour les anciennes versions, nous devons boucler:

<*>\n''newline.bar' 'has space.bar' 'has*.bar'

Lecture dans un tableau:

<*>

readarray -d nécessite Bash 4.4 ou plus récent. Pour les anciennes versions, nous devons boucler:

<*>

Faites attention à la solution Perl suggérée: elle supprime tout ce qui se trouve 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 le nom de base "$ x" .ext si vous connaissez la extension) sont beaucoup plus simples.

Le nom de base fait cela, supprime le chemin. Il supprimera également le suffixe s'il est indiqué et s'il correspond au suffixe du fichier, mais vous devez connaître le suffixe à attribuer à la commande. Sinon, vous pouvez utiliser mv et déterminer ce que le nouveau nom doit être autrement.

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

$ x="/foo/fizzbuzz.bar.quux"
$ y=(`basename ${x%%.*}`)
$ echo $y
fizzbuzz
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top