Quiero leer un archivo y guardarlo en una variable, pero necesito mantener la variable y no sólo imprimir el archivo. ¿Cómo puedo hacer esto? He escrito este script pero no es lo que necesitaba:
#!/bin/sh
while read LINE
do
echo $LINE
done <$1
echo 11111-----------
echo $LINE
En mi script, puedo dar el nombre del archivo como un parámetro, por lo que, si el archivo contiene "aaaa", por ejemplo, se imprimiría esto:
aaaa
11111-----
Pero esto sólo imprime el archivo en la pantalla, ¡y yo quiero guardarlo en una variable! ¿Hay alguna manera fácil de hacer esto?
En la plataforma cruzada, el mínimo común denominador sh
se utiliza:
#!/bin/sh
value=`cat config.txt`
echo "$value"
En bash
o zsh
, para leer un archivo completo en una variable sin invocar cat
:
#!/bin/bash
value=$(<config.txt)
echo "$value"
Invocar cat
en bash
o zsh
para sorber un archivo se consideraría un Useless Use of Cat.
Tenga en cuenta que no es necesario citar la sustitución del comando para preservar las nuevas líneas.
Ver: Bash Hacker's Wiki - Sustitución de comandos - Especialidades.
Dos importantes escollos
que fueron ignorados por otras respuestas hasta ahora:
2. Eliminación de la nueva línea final de la expansión de comandos
Este es un problema para el:
value="$(cat config.txt)"
pero no para las soluciones basadas en read
.
La expansión de comandos elimina las nuevas líneas finales:
S="$(printf "a\n")"
printf "$S" | od -tx1
Salidas:
0000000 61
0000001
Esto rompe el método ingenuo de lectura de archivos:
FILE="$(mktemp)"
printf "a\n\n" > "$FILE"
S="$(<"$FILE")"
printf "$S" | od -tx1
rm "$FILE"
Solución POSIX: añadir un carácter extra a la expansión del comando y eliminarlo después:
S="$(cat $FILE; printf a)"
S="${S%a}"
printf "$S" | od -tx1
Salidas:
0000000 61 0a 0a
0000003
Solución casi POSIX: Codificación ASCII. Véase más abajo.
Eliminación del carácter NUL.
No existe una forma sana de almacenar caracteres NUL en las variables.
Esto afecta tanto a las soluciones de expansión como a las de read
, y no conozco ninguna buena solución para ello.
Ejemplo:
printf "a\0b" | od -tx1
S="$(printf "a\0b")"
printf "$S" | od -tx1
Salidas:
0000000 61 00 62
0000003
0000000 61 62
0000002
¡Ja, nuestro NUL ha desaparecido!
Soluciones:
Codificación ASCII. Ver abajo.
utilizar los literales de la extensión bash $""
:
S=$"a\N0b"
printf "$S" | od -tx1
Sólo funciona para los literales, por lo que no es útil para la lectura de archivos.
Resolución de los problemas
Almacenar una versión codificada en uuencode base64 del archivo en la variable, y decodificar antes de cada uso:
FILE="$(mktemp)"
printf "a\0\n" > "$FILE"
S="$(uuencode -m "$FILE" /dev/stdout)"
uudecode -o /dev/stdout <(printf "$S") | od -tx1
rm "$FILE"
Salida:
0000000 61 00 0a
0000003
uuencode y udecode son POSIX 7 pero no están en Ubuntu 12.04 por defecto (paquete sharutils
)... No veo una alternativa POSIX 7 para la extensión de sustitución del proceso bash <()
excepto escribir en otro archivo...
Por supuesto, esto es lento e inconveniente, así que supongo que la respuesta real es: no usar Bash si el archivo de entrada puede contener caracteres NUL.