scripts script resueltos programas paso pasar parametros hacer español ejercicios ejemplos como comandos shell unix sh

shell - programas - scripts linux ejercicios resueltos



¿Cómo leer un archivo en una variable en shell? (5)

Quiero leer un archivo y guardarlo en una variable, pero necesito mantener la variable y no solo imprimir el archivo. ¿Cómo puedo hacer esto? He escrito este guión pero no es exactamente 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 parámetro, por lo tanto, si el archivo contiene "aaaa", por ejemplo, imprimirá esto:

aaaa 11111-----

¡Pero esto solo imprime el archivo en la pantalla, y quiero guardarlo en una variable! ¿Hay una forma fácil de hacer esto?


Como señala Ciro Santilli utilizando sustituciones de comandos, se eliminarán las nuevas líneas. Su solución para agregar caracteres finales es genial, pero después de usarla durante bastante tiempo, decidí que necesitaba una solución que no usara la sustitución de comandos.

Mi enfoque ahora usa read junto con el printf printv builtin -v para leer el contenido de stdin directamente en una variable.

# Reads stdin into a variable, accounting for trailing newlines. Avoids needing a subshell or # command substitution. read_input() { # Use unusual variable names to avoid colliding with a variable name # the user might pass in (notably "contents") : "${1:?Must provide a variable to read into}" if [[ "$1" == ''_line'' || "$1" == ''_contents'' ]]; then echo "Cannot store contents to $1, use a different name." >&2 return 1 fi local _line _contents while read -r _line; do _contents="${_contents}${_line}"$''/n'' done _contents="${_contents}${_line}" # capture any content after the last newline printf -v "$1" ''%s'' "$_contents" }

Esto admite entradas con o sin nuevas líneas finales.

Ejemplo de uso:

$ read_input file_contents < /tmp/file # $file_contents now contains the contents of /tmp/file


En multiplataforma, el mínimo común denominador usará:

#!/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 uso inútil de cat .

Tenga en cuenta que no es necesario citar la sustitución de comandos para conservar las nuevas líneas.

Ver: Wiki de Bash Hacker - Sustitución de comandos - Especialidades .


Si quieres leer todo el archivo en una variable:

#!/bin/bash value=`cat sources.xml` echo $value

Si quieres leerlo línea por línea:

while read line; do echo $line done < file.txt


esto funciona para mí: v=$(cat <file_path>) echo $v


Dos escollos importantes

que fueron ignoradas por otras respuestas hasta el momento:

  1. Remolque eliminación de nueva línea de la expansión de comando
  2. Eliminación de caracteres NUL

Remolque eliminación de nueva línea de la expansión de comando

Este es un problema para el:

value="$(cat config.txt)"

Soluciones tipo, pero no para 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 ingenuo método de leer archivos:

FILE="$(mktemp)" printf "a/n/n" > "$FILE" S="$(<"$FILE")" printf "$S" | od -tx1 rm "$FILE"

Solución POSIX: agregue un carácter adicional a la expansión del comando y elimínelo más tarde:

S="$(cat $FILE; printf a)" S="${S%a}" printf "$S" | od -tx1

Salidas:

0000000 61 0a 0a 0000003

Casi la solución POSIX: codificación ASCII. Vea abajo.

Eliminación de caracteres NUL

No hay una forma sensata de Bash para almacenar caracteres NUL en variables .

Esto afecta tanto a las soluciones de expansión como de read , y no conozco ninguna solución adecuada 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

Ha, nuestro NUL se ha ido!

Soluciones:

  • Codificación ASCII. Vea abajo.

  • usar la extensión bash $"" literales:

    S=$"a/0b" printf "$S" | od -tx1

    Solo funciona para literales, por lo que no es útil para leer desde archivos.

Solución para las trampas

Almacene una versión codificada en uuencode base64 del archivo en la variable, y descodifique 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 la escritura en otro archivo ...

Por supuesto, esto es lento e inconveniente, así que supongo que la respuesta real es: no use Bash si el archivo de entrada puede contener caracteres NUL.