scripts script resueltos programas pasar parametros operaciones manejo entorno ejercicios ejemplos cadenas aritmeticas bash null-character

script - Asigne una cadena que contenga caracteres nulos(/ 0) a una variable en Bash



scripts linux ejercicios resueltos (4)

Al tratar de procesar una lista de nombres de archivo / carpeta correctamente ( vea mis otras preguntas ) mediante el uso de un carácter NULO como delimitador, me topé con un extraño comportamiento de Bash que no entiendo

Cuando se asigna una cadena que contiene uno o más caracteres NULL a una variable, los caracteres NULL se pierden / ignoran / no se almacenan.

Por ejemplo,

echo -ne "n/0m/0k" | od -c # -> 0000000 n /0 m /0 k

Pero:

VAR1=`echo -ne "n/0m/0k"` echo -ne "$VAR1" | od -c # -> 0000000 n m k

Esto significa que necesitaría escribir esa cadena en un archivo (por ejemplo, en / tmp) y leerla desde allí si la canalización directamente no es deseada o factible.

Al ejecutar estos scripts en el shell Z (zsh), las cadenas que contienen / 0 se conservan en ambos casos, pero lamentablemente no puedo asumir que zsh esté presente en los sistemas que ejecutan mi script, mientras que Bash debería estarlo.

¿Cómo pueden almacenarse o manejarse eficientemente las cadenas que contienen caracteres / 0 sin perder ningún (meta) carácter?


Como ya han dicho otros, no puede almacenar / usar caracteres NUL :

  • en una variable
  • En un argumento de la línea de comando.

Sin embargo, puede manejar cualquier dato binario (incluido el carácter NUL):

  • en pipas
  • en archivos

Así que para responder a tu última pregunta:

¿Alguien puede darme una pista de cómo las cadenas que contienen caracteres / 0 pueden almacenarse o manejarse de manera eficiente sin perder ningún (meta) carácter?

Puede usar archivos o tuberías para almacenar y manejar eficientemente cualquier cadena con cualquier meta-caracteres.

Si planea manejar datos, debe tener en cuenta además que:

  • Solo la charla NUL será devorada por la variable y el argumento de la línea de comando, puede verificar esto .
  • Tenga cuidado de que la sustitución de comandos (como $(command..) o `command..` $(command..) `command..` ) tiene un giro adicional por encima de ser una variable, ya que comerá sus líneas finales .

Limitaciones de bypass

Si desea usar variables, debe deshacerse del carácter NUL codificándolo, y varias otras soluciones aquí ofrecen formas inteligentes de hacerlo (una forma obvia es utilizar, por ejemplo, la codificación / decodificación de base64).

Si le preocupa la memoria o la velocidad, es probable que desee utilizar un analizador mínimo y solo citar el carácter NUL (y el carácter de cita). En este caso esto te ayudaría:

quote() { sed ''s/////////g;s//x0///0/g''; }

Luego, puede asegurar sus datos antes de almacenarlos en variables y argumentos de la línea de comandos al ingresar sus datos confidenciales en una quote , lo que generará un flujo de datos seguro sin caracteres NUL. Puede recuperar la cadena original (con caracteres NUL) usando echo -en "$var_quoted" que enviará la cadena correcta en la salida estándar.

Ejemplo:

## Our example output generator, with NUL chars ascii_table() { echo -en "$(echo ''/'0{0..3}{0..7}{0..7} | tr -d " ")"; } ## store myvar_quoted=$(ascii_table | quote) ## use echo -en "$myvar_quoted"

Nota: utilizar | hd | hd para obtener una vista clara de sus datos en hexadecimal y verificar que no haya perdido ningún carácter NUL.

Herramientas de cambio

Recuerde que puede ir bastante lejos con tuberías sin utilizar variables ni argumentos en la línea de comandos, no olvide, por ejemplo, la construcción <(command ...) que creará una tubería con nombre (una especie de archivo temporal).

EDITAR: la primera implementación de la quote fue incorrecta y no trataría correctamente con los caracteres especiales interpretados por echo -en . Gracias @xhienne por ver eso.


En Bash, no puede almacenar el carácter NULL en una variable.

Sin embargo, puede almacenar un volcado hexadecimal simple de los datos (y luego revertir esta operación nuevamente) usando el comando xxd .

VAR1=`echo -ne "n/0m/0k" | xxd -p | tr -d ''/n''` echo -ne "$VAR1" | xxd -r -p | od -c # -> 0000000 n /0 m /0 k


Me encanta la respuesta de jeff . Yo usaría la codificación Base64 en lugar de xxd. Ahorra un poco de espacio y sería (creo) más reconocible en cuanto a lo que se pretende.

VAR=$(echo -n "foo/0bar" | base64) echo -n $VAR | base64 -d | xargs -0 ...

En cuanto a -e, no es necesario porque el shell ya interpreta el escape antes de que incluso se haga eco. También me parece recordar que algo acerca de que "echo -e" es inseguro si está haciendo eco de cualquier entrada del usuario, ya que podrían inyectar secuencias de escape que el eco interpretará y terminarán con cosas malas.


Use uuencode y uudecode para la portabilidad POSIX

xxd y base64 no son POSIX 7, pero uuencode sí lo es .

VAR="$(uuencode -m <(printf "a/0/n") /dev/stdout)" uudecode -o /dev/stdout <(printf "$VAR") | od -tx1

Salida:

0000000 61 00 0a 0000003

Desafortunadamente, no veo una alternativa POSIX 7 para la extensión de sustitución del proceso Bash <() excepto la escritura en el archivo, y no están instaladas en Ubuntu 12.04 de forma predeterminada (paquete sharutils ).

Así que supongo que la verdadera respuesta es: no uses Bash para esto, usa Python o algún otro lenguaje interpretado más sensato.