web-dev-qa-db-fra.com

Concaténation de deux variables avec un trait de soulignement

J'ai besoin de concaténer deux variables pour créer un nom de fichier avec un trait de soulignement. Permet d'appeler mes variables $FILENAME et $EXTENSION où le nom de fichier est lu dans un fichier.

FILENAME=Hello
EXTENSION=WORLD.txt

Maintenant...

J'ai essayé ce qui suit sans succès:

NAME=${FILENAME}_$EXTENSION
NAME=${FILENAME}'_'$EXTENSION
NAME=$FILENAME\\_$EXTENSION

J'obtiens toujours une sorte de sortie bizarre. Habituellement, le trait de soulignement en premier.

J'en ai besoin

echo $NAME
Hello_WORLD.txt
62
Rhyuk

Vous pouvez utiliser quelque chose comme ceci:

NAME=$(echo ${FILENAME}_${EXTENSION})

Cela fonctionne également:

NAME=${FILENAME}_${EXTENSION}
74
Tim

Votre:

NAME=${FILENAME}_$EXTENSION
NAME=${FILENAME}'_'$EXTENSION

sont tous très bien, serait donc:

NAME=${FILENAME}_${EXTENSION}
NAME=$FILENAME'_'$EXTENSION
NAME=$FILENAME\_$EXTENSION
NAME=$FILENAME"_$EXTENSION"

(mais certainement pas  NAME=$(echo ${FILENAME}_${EXTENSION}) as il utilise echo et l'opérateur split+glob ).

NAME=$FILENAME_$EXTENSION

aurait été le même que:

NAME=${FILENAME_}${EXTENSION}

car _ (contrairement à \ ou ') est un caractère valide dans un nom de variable.

Votre problème est que vous aviez des lignes délimitées par CRLF au lieu de simplement LF, ce qui signifiait que le contenu de ces variables se terminait par le caractère CR.

Le caractère CR, lorsqu'il est écrit sur un terminal, indique au terminal de déplacer le curseur au début de la ligne. Ainsi, Hello<CR>_WORLD.TXT<CR> Lorsqu'il est envoyé à un terminal s'affichera comme _WORLD.TXT (En remplaçant Hello).

13
Stéphane Chazelas

Je suis passé à l'utilisation de la syntaxe ${FILENAME}_${EXTENSION} Mentionnée ci-dessus.

J'avais l'habitude d'utiliser $() quand j'avais besoin de concaténer deux variables avec un trait de soulignement. Par exemple, $YYYYMMDD$()_$HHMMSS pour générer un nom de fichier contenant un horodatage au format YYYYMMDD_HHMMSS. La fonction $() du milieu ne renvoie rien et sépare les deux variables.

J'ai utilisé time pour mesurer les affectations en utilisant la méthode $YYYYMMDD$()_$HHMMSS et certaines de celles ci-dessus, et ils ont tous signalé 0 ms sur l'ancien serveur sur lequel j'utilise ceci. Les performances ne semblent pas être un problème.

1
user208145

réponse de Stéphane Chazelas ,

NAME=${FILENAME}_$EXTENSION

est, bien sûr, la meilleure réponse, et devrait être la réponse acceptée. Mais, dans l'esprit de réponse de user208145 , voici une alternative:

UNDERSCORE='_'
NAME=$FILENAME$UNDERSCORE$EXTENSION

Vous devez utiliser des variables en minuscules (c'est la meilleure pratique).
Donc, j'utiliserai le nom de fichier et l'extension au lieu de FILENAME et EXTENSION

Comme vous dites que "le nom de fichier est lu à partir d'un fichier", je suppose que le script est:

read -r filename  <file.txt
extension=World.txt

Et que vous souhaitez concaténer les deux variables $ filename et $ extension avec un trait de soulignement _.
Les exemples que vous fournissez (sauf: pas de double \) fonctionnent correctement ici:

name=${filename}_$extension
name=${filename}'_'$extension
name=$filename\_$extension

Comme certains autres:

name="${filename}"'_'"${extension}"
name="$filename"'_'"$extension"
name="${filename}_${extension}"

Donc, votre problème n'est pas avec la façon dont les variables sont collées ensemble, mais avec le contenu des vars. Il semble raisonnable de penser que ceci:

read -r filename  <file.txt

va lire un retour chariot fin \r si vous lisez un fichier Windows.

Une solution simple (pour ksh, bash, zsh) consiste à supprimer tous les caractères de contrôle de la variable lue:

filename=${filename//[[:cntrl:]]/}

Cela pourrait être simulé avec une valeur qui a un retour chariot:

$ filename=$'Hello\r'
$ echo "starting<$filename>end"
>endting<Hello                       ### note the return to the start of line.
$ echo "starting<${filename//[[:cntrl:]]/}>end"
starting<Hello>end

Ou, en remplaçant la valeur de filename:

$ filename="${filename//[[:cntrl:]]/}"
$ echo "start<$filename>end"
start<Hello>end

Conclusion.

Donc ça:

name="${filename//[[:cntrl:]]/}_${extension//[[:cntrl:]]/}"

Obtiendra la valeur correcte pour name même si les autres variables contiennent des caractères de contrôle.

0
user79743