J'essaie de définir une variable dans un script sh sur les 3 derniers caractères du nom de base d'un fichier (par nom de base, je veux dire sans le chemin et sans le suffixe). J'ai réussi à le faire mais, par pure curiosité, je me demande s'il y a une commande unique plus courte que je peux utiliser. À l'origine, j'avais un monoplace avec awk
, mais c'était plutôt long. Actuellement, j'ai ce script à deux lignes (en supposant qu'un nom de fichier complet se trouve $1
):
filebase=`basename "$1"`
lastpart=`echo -n ${filebase%.*} | tail -c3`
Ainsi, par exemple, "/path/to/somefile.txt" se termine par "ile" dans $lastpart
.
Puis-je en quelque sorte combiner basename
et le bit pour supprimer le suffixe en une seule commande, et existe-t-il un moyen de l'envoyer à tail
(ou autre chose que je peux utiliser) sans utiliser de canal? Le suffixe est inconnu, je ne peux donc pas le baser en tant que paramètre sur basename
.
L'objectif principal n'est pas vraiment d'être aussi court que possible, mais d'être aussi lisible d'un coup d'œil que possible. Le contexte réel de tout cela est cette question sur Superuser , où j'essaie de trouver une réponse assez simple.
la source
file.one.two.three
? Souhaitez-vousile
outwo
?two
fonctionnerait; l'extension sur ce serait.three
je suppose.Réponses:
C'est un travail typique pour
expr
:Si vous savez que les noms de vos fichiers ont le format attendu (contient un et un seul point et au moins 3 caractères avant le point), cela peut être simplifié pour:
Notez que l'état de sortie sera différent de zéro s'il n'y a pas de correspondance, mais également si la partie correspondante est un nombre qui se résout à 0. (comme pour
a000.txt
oua-00.txt
)Avec
zsh
:(
:t
pour queue (nom de base),:r
pour reste (avec extension supprimée)).la source
expr
est un autre dont je dois me familiariser. J'aime vraiment leszsh
solutions en général (je lisais à propos de son support pour les substitutions imbriquées sur le côté gauche d'un${}
hier aussi et souhaitantsh
avoir la même chose), c'est juste une déception qu'il n'est pas toujours présent par défaut.expr
n'était pas POSIX. C'est certainement. Il est cependant rarement intégré.Cela supprime d'abord les trois derniers caractères de
$var
puis supprime$var
les résultats de cette suppression - qui renvoie les trois derniers caractères de$var
. Voici quelques exemples plus spécifiquement destinés à démontrer comment vous pourriez faire une telle chose:Vous n'avez pas à répartir tout cela à travers autant de commandes. Vous pouvez compacter ceci:
La combinaison
$IFS
avecset
les paramètres de shell ting peut également être un moyen très efficace d'analyser et de parcourir les variables de shell:Cela ne vous donnera que les trois caractères précédant immédiatement la première période suivant la dernière
/
entrée$path
. Si vous souhaitez récupérer uniquement les trois premiers caractères précédant immédiatement le dernier.
dans$path
(par exemple, s'il existe une possibilité de plus d'un.
nom de fichier) :Dans les deux cas, vous pouvez faire:
Et...
... imprimera ce qui suit le
.
Si cela ne vous dérange pas d'utiliser un programme externe, vous pouvez faire:
S'il y a une chance qu'un
\n
caractère ewline dans le nom de fichier (ne s'applique pas aux solutions de shell natives - ils gèrent tous cela de toute façon) :la source
$base
là, le mieux que j'ai pu faire était le trioname=${var##*/} ; base=${name%%.*} ; lastpart=${base#${base%???}}
. Sur le plan positif, c'est pur bash, mais c'est toujours 3 lignes. (Dans votre exemple de "/tmp/file.txt", j'aurais besoin de "ile" plutôt que de "file".) Je viens d'apprendre beaucoup de choses sur la substitution de paramètres; Je ne savais pas que ça pouvait faire ça ... assez pratique. Je le trouve également très lisible, personnellement.%
au lieu de%%
supprimer le suffixe, et je n'ai pas vraiment besoin de supprimer le chemin, donc je peux obtenir une ligne deux plus agréablenoextn=${var%.*} ; lastpart=${noextn#${noextn%???}}
.$IFS
en a${noextn}
et vous ne citez pas l'extension. Donc, c'est plus sûr:lastpart=${noextn#"${noextn%???}"}
Si vous pouvez utiliser
perl
:la source
perl -e 'shift =~ /(.{3})\.[^.]*$/ && print $1' $filename
. Un supplémentbasename
serait nécessaire si le nom de fichier ne peut contenir aucun suffixe mais que certains répertoires du chemin en contiennent.perl -e 'shift =~ m#(.{3})(?:\.[^./]*)?$# && print $1' $filename
sed
travaille pour cela:Ou
Si votre
sed
ne prend pas en charge-r
, remplacez simplement les instances de()
avec\(
et\)
, et alors ce-r
n'est pas nécessaire.la source
Si perl est disponible, je trouve qu'il peut être plus lisible que d'autres solutions, notamment parce que son langage d'expression
/x
régulière est plus expressif et qu'il a le modificateur, qui permet d'écrire des expressions régulières plus claires:Cela n'imprime rien s'il n'y a pas une telle correspondance (si le nom de base n'a pas d'extension ou si la racine avant l'extension est trop courte). Selon vos besoins, vous pouvez ajuster l'expression régulière. Cette expression régulière applique les contraintes:
L'utilisation de ceci dans une substitution de commande a le problème normal de supprimer trop de nouvelles lignes de fin, un problème qui affecte également la réponse de Stéphane. Il peut être traité dans les deux cas, mais c'est un peu plus facile ici:
la source
Python2.7
la source
Je pense que cette fonction bash, pathStr (), fera ce que vous recherchez.
Il ne nécessite pas awk, sed, grep, perl ou expr. Il n'utilise que des commandes bash, donc c'est assez rapide.
J'ai également inclus les fonctions argsNumber et isOption dépendantes mais leurs fonctionnalités pourraient être facilement incorporées dans pathStr.
La fonction dépendante ifHelpShow n'est pas incluse car elle a de nombreuses sous-dépendances pour la sortie du texte d'aide soit sur la ligne de commande du terminal, soit dans une boîte de dialogue GUI via YAD . Le texte d'aide qui lui est transmis est inclus pour la documentation. Indiquez si vous souhaitez ifHelpShow et ses dépendants.
RESSOURCES
la source
bash
ismes - apparemment plus simple que cela. Et qu'est-ce que c'est${#@}
?$#
c'est la syntaxe du nombre d'arguments, et elle est également utilisée ailleurs ici.${#@}
n'est pas équivalent dans la plupart des cas - la spécification POSIX indique les résultats de toute extension de paramètre sur l'un$@
ou l' autre ou$*
n'est pas spécifié, malheureusement. Cela peut fonctionner,bash
mais ce n'est pas une fonctionnalité fiable, je suppose que c'est ce que j'essaie de dire.,