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
Vous pouvez utiliser quelque chose comme ceci:
NAME=$(echo ${FILENAME}_${EXTENSION})
Cela fonctionne également:
NAME=${FILENAME}_${EXTENSION}
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 as il utilise NAME=$(echo ${FILENAME}_${EXTENSION})
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
).
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.
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
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.