Noms de fichiers donnés comme ceux-ci:
/the/path/foo.txt
bar.txt
J'espère avoir:
foo
bar
Pourquoi ça ne marche pas?
#!/bin/bash
fullfile=$1
fname=$(basename $fullfile)
fbname=${fname%.*}
echo $fbname
Quelle est la bonne façon de le faire?
Vous n'êtes pas obligé d'appeler la commande externe basename
. À la place, vous pouvez utiliser les commandes suivantes:
$ s=/the/path/foo.txt
$ echo ${s##*/}
foo.txt
$ s=${s##*/}
$ echo ${s%.txt}
foo
$ echo ${s%.*}
foo
Notez que cette solution devrait fonctionner dans tous les récents ( post 2004 ) POSIX coques compatibles, (par exemple bash
, dash
, ksh
, etc.).
Source: Expansion des paramètres du langage de commande Shell 2.6.2
Plus d'informations sur les manipulations de chaîne bash: http://tldp.org/LDP/LG/issue18/bash.html
La commande nom_base a deux invocations différentes; dans l'un, vous spécifiez uniquement le chemin, auquel cas il vous donne le dernier composant, tandis que dans l'autre, vous donnez également un suffixe qu'il supprimera. Ainsi, vous pouvez simplifier votre exemple de code en utilisant la deuxième invocation de basename. Veillez également à citer correctement les choses:
fbname = $ (nom de base "$ 1" .txt) echo "$ fbname"
Une combinaison du nom de base et de la coupe fonctionne bien, même en cas de fin double comme .tar.gz
:
fbname=$(basename "$fullfile" | cut -d. -f1)
Ce serait intéressant si cette solution nécessitait moins de puissance arithmétique que Bash Parameter Expansion.
Pure bash
, pas de basename
, pas de jonglerie variable. Définissez une chaîne et echo
:
s=/the/path/foo.txt
echo ${s//+(*\/|.*)}
Sortie:
foo
Remarque: l’option bash
extglob doit être "on", (bunt définit extglob "on" par défaut), si ce n'est pas le cas, faites:
shopt -s extglob
En parcourant la ${s//+(*\/|.*)}
:
${s
- commencez par $ s.//
substitue chaque instance du motif.+(
correspond à n ou plusieurs de la liste de modèles entre parenthèses, (i.e. jusqu'au point 7 ci-dessous).*\/
correspond à tout ce qui précède un caractère "/
" littéral.|
qui, dans ce cas, agit comme un OU logique ..*
ne fait rien après un ".
" littéral - c'est-à-dire que, dans bash
, le ".
" n'est qu'un point char, et not n point regex .)
end liste de modèles.}
fin le développement des paramètres. Avec une substitution de chaîne, il y a généralement un autre /
, suivi d'une chaîne de remplacement. Mais comme il n'y a pas de /
ici, les modèles correspondants ne sont remplacés par rien; cela supprime les correspondances.Arrière-plan man bash
pertinent:
${parameter/pattern/string} Pattern substitution. The pattern is expanded to produce a pat‐ tern just as in pathname expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. If pattern begins with /, all matches of pattern are replaced with string. Normally only the first match is replaced. If pattern begins with #, it must match at the begin‐ ning of the expanded value of parameter. If pattern begins with %, it must match at the end of the expanded value of parameter. If string is null, matches of pattern are deleted and the / fol‐ lowing pattern may be omitted. If parameter is @ or *, the sub‐ stitution operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with @ or *, the substitution operation is applied to each member of the array in turn, and the expansion is the resultant list.
If the extglob Shell option is enabled using the shopt builtin, several extended pattern matching operators are recognized. In the following description, a pattern-list is a list of one or more patterns separated by a |. Composite patterns may be formed using one or more of the fol‐ lowing sub-patterns: ?(pattern-list) Matches zero or one occurrence of the given patterns *(pattern-list) Matches zero or more occurrences of the given patterns +(pattern-list) Matches one or more occurrences of the given patterns @(pattern-list) Matches one of the given patterns !(pattern-list) Matches anything except one of the given patterns
Voici les oneliners:
$(basename ${s%.*})
$(basename ${s} .${s##*.})
J'avais besoin de ça, comme l'ont demandé bongbang et w4etwetewtwet.
Voici un autre moyen (plus complexe) d'obtenir le nom de fichier ou l'extension. Commencez par utiliser la commande rev
pour inverser le chemin du fichier. Coupez-le à partir du premier .
, puis inversez-le à nouveau, comme ceci: :
filename=`rev <<< "$1" | cut -d"." -f2- | rev`
fileext=`rev <<< "$1" | cut -d"." -f1 | rev`
Si vous voulez jouer à Nice avec les chemins de fichiers Windows (sous Cygwin), vous pouvez aussi essayer ceci:
fname=${fullfile##*[/|\\]}
Cela tiendra compte des séparateurs de barre oblique inverse lors de l'utilisation de BaSH sous Windows.
Juste une alternative que j'ai imaginé pour extraire une extension, en utilisant les posts de ce fil avec ma propre petite base de connaissances qui m’était plus familière.
ext="$(rev <<< "$(cut -f "1" -d "." <<< "$(rev <<< "file.docx")")")"
Note: S'il vous plaît conseiller sur mon utilisation des guillemets; cela a fonctionné pour moi mais il se peut que je manque quelque chose sur leur bon usage (j'en utilise probablement trop).