Concatenando dos variables con un guión bajo


54

Necesito concatenar dos variables para crear un nombre de archivo que tenga un guión bajo. Llamemos a mis variables $FILENAMEy $EXTENSIONdónde se lee el nombre de archivo de un archivo.

FILENAME=Hello
EXTENSION=WORLD.txt

Ahora...

He intentado lo siguiente sin éxito:

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

Siempre obtengo algún tipo de salida extraña. Por lo general, el guión bajo primero.

Necesito que sea

echo $NAME
Hello_WORLD.txt

2
Probablemente su script contiene caracteres de retorno de carro.
Stéphane Chazelas

Sí, eso fue todo. : D
Rhyuk

Respuestas:


67

Puedes usar algo como esto:

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

Esto también funciona:

NAME=${FILENAME}_${EXTENSION}

1
El problema era el archivo en el que estaba leyendo NAME. Formateo de Windows ... Su solución funcionó muy bien después de eso. Gracias
Rhyuk

2
El primer comando destruye el valor de la variable y el uso de una sustitución de comando y echono puede ayudar. El segundo comando ya fue dado en la pregunta.
Gilles 'SO- deja de ser malvado'

1
¡Si! Me encanta. Esto fue jodidamente molesto por mucho tiempo. Gracias por la solucion!
racl101

Esto funciona para mi. Cuando uso '$ FILENAME_ $ EXTENSION', solo aparecen los valores de '$ EXTENSION'. ¿Podrías ayudarme a explicar por qué sucede esto? Gracias
Lei Hao

12

Tu:

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

están todos bien, así sería:

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

(pero ciertamente no NAME=$(echo ${FILENAME}_${EXTENSION}) como lo usaecho y el split+globoperador ).

NAME=$FILENAME_$EXTENSION

habría sido lo mismo que:

NAME=${FILENAME_}${EXTENSION}

como _(contrario a \o ') es un carácter válido en un nombre de variable.

Su problema es que tenía líneas delimitadas con CRLF en lugar de solo LF, lo que significaba que ese contenido variable terminaba en caracteres CR.

El carácter CR, cuando se escribe en un terminal, le dice al terminal que mueva el cursor al comienzo de la línea. Entonces, Hello<CR>_WORLD.TXT<CR>cuando se envía a una terminal, se mostrará como _WORLD.TXT(anulando el Hello).


1

He cambiado a usar la ${FILENAME}_${EXTENSION}sintaxis mencionada anteriormente.

Solía ​​usar $()cuando necesitaba concatenar dos variables con un guión bajo. Por ejemplo, $YYYYMMDD$()_$HHMMSSpara generar un nombre de archivo que contenga una marca de tiempo en el formato AAAAMMDD_HHMMSS. El medio $()no devuelve nada y separa las dos variables.

Solía timemedir las asignaciones usando el $YYYYMMDD$()_$HHMMSSmétodo y algunas de las anteriores, y todas han reportado 0 ms en el servidor anterior en el que estoy usando esto. El rendimiento no parece ser un problema.


Eso no responde la pregunta. Deberías plantear una nueva pregunta para eso. $()bifurca un subshell en unos pocos shells (algunos lo optimizan). También está secuestrando a un operador para algo para lo que no ha sido diseñado. ${x}_yes lo que quieres
Stéphane Chazelas

¿Qué quieres decir con "Eso no responde la pregunta"? No es una gran respuesta, pero es una respuesta.
Scott

Editado para eliminar la ambigüedad.
user208145

0

Debe usar variables en minúsculas (es la mejor práctica).
Por lo tanto, usaré el nombre de archivo y la extensión en lugar de FILENAME y EXTENSION

Cuando diga que "el nombre de archivo se lee de un archivo", supondré que el script es:

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

Y que desea concatenar ambas variables $ filename y $ extension con un guión bajo _.
Los ejemplos que proporciona (excepto: no double \) funcionan correctamente aquí:

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

Como algunos otros:

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

Por lo tanto, su problema no es cómo se unen las variables, sino con el contenido de los vars. Parece razonable pensar que esto:

read -r filename  <file.txt

leerá un retorno de carro final \rsi lee desde un archivo de Windows.

Una solución simple (para ksh, bash, zsh) es eliminar todos los caracteres de control de la variable de lectura:

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

Esto podría simularse con un valor que tenga un retorno de carro:

$ 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

O, reemplazando el valor de filename:

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

Conclusión.

Así que esto:

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

Obtendrá el valor correcto nameincluso si los otros vars contienen caracteres de control.



-2

También puede usar esto: separe los vars separados con espacios y concatenelos usando tr para eliminar el espacio.

TableNameToCreate="MyTable"
# concatenation work is done here 
$(echo "$TableNameToCreate _my_other_Info " | tr -d " ")

#Proof
echo "Var to create with var pasted as prefix to suffix
    $(echo "$TableNameToCreate _my_other_Info " | tr -d " ") 
. "

# create a new var
NewVar=$(echo "$TableNameToCreate _my_other_Info " | tr -d " ")

#proof
echo "$NewVar"

(1) Esta pregunta ya ha sido respondida más que adecuadamente. (2) ¿Qué hace su respuesta si la variable existente tiene caracteres especiales?
G-Man dice 'Restablecer a Monica' el

Esto no soluciona el problema con la variable que contiene un retorno de carro. También elimina espacios, algo que puede no ser deseado.
Kusalananda

@Kusalananda: En realidad, a menos que esté pasando por alto algo, esto maneja el retorno de carro muy bien; Los espacios son el único problema.
G-Man dice 'reinstalar a Monica' el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.