¿Cómo pasar el valor de una variable al stdin de un comando?


105

Estoy escribiendo un script de shell que debería ser algo seguro, es decir, no pasa datos seguros a través de parámetros de comandos y preferiblemente no usa archivos temporales. ¿Cómo puedo pasar una variable al stdin de un comando? O, si no es posible, ¿cómo utilizar correctamente los archivos temporales para dicha tarea?


¿Puede un atacante cambiar $PATH? Para que catpueda ser reemplazado/bin/cat "$@" | tee /attacker/can/read/this/file
12431234123412341234123

Respuestas:


74

Algo tan simple como:

echo "$blah" | my_cmd

7
Cuidado con los espacios en tu variable: echo "$blah"es mejor.
Jonathan Leffler

13
Veamos cómo lo manejas blah=-n, blah=-e... usa printfen su lugar. unix.stackexchange.com/questions/65803/…
Camilo Martin

1
esto parece que sería frágil y propenso a errores, ¿no?
ThorSummoner

20
6 años después, si pudiera eliminar esta respuesta, lo haría (pero no puedo porque ha sido aceptada ...)
Oliver Charlesworth

1
@OliverCharlesworth, ¿por qué no editarlo para usarlo printf '%s\n' "$blah"? Con ese cambio (evitando las muchas trampas en echola especificación, que la excelente respuesta de Stephane entra en detalle en ¿Por qué es printfmejor que echo? En Unix y Linux , o que la sección de USO DE APLICACIONES de la echoespecificación toca más brevemente) es un perfecto respuesta razonable.
Charles Duffy

192

Pasar un valor a stdinen bash es tan simple como:

your-command <<< "$your_variable"

¡Siempre asegúrese de poner comillas alrededor de las expresiones variables!

Tenga cuidado, ya que esto probablemente funcionará solo en bashy no funcionará en sh.


39
No <<<se garantiza que estas cadenas estén disponibles, no están en la base POSIX, hasta donde yo sé. Funcionarán como se espera, siempre y cuando solo los ejecute bash. Solo lo menciono, porque OP dijeron 'shell', no específicamente 'bash'. Aunque etiquetó la pregunta con bash... así que obviamente esta es una respuesta aceptable.
JM Becker

Si bien este puede ser el caso, es probable que la información confidencial se filtre más fácilmente si se usa el echométodo debido a la creación de una tubería. El comando herestring será procesado por completo bash, aunque en esta situación (como se indicó) es mejor que sepa que funcionará en su bash, de lo contrario, cualquier mensaje de error producido como resultado de no admitir herestrings también filtraría dicha información.
Steven Lu

@StevenLu Wait, echoes una función de. No hay tubería allí, ¿verdad? Es Unix, pero no puede ser tanto Unix .
Camilo Martin

4
@StevenLu printf '%s\n' "$var"produce los mismos resultados que echo "$var"pero no se romperá si, por ejemplo var=-en, y ni siquiera requiere bash.
Camilo Martin

1
Tenga en cuenta también que se agrega una nueva línea a la cadena de aquí cadenas.
pdr

19

Tenga en cuenta que las echo "$var" | commandoperaciones ' significan que la entrada estándar se limita a las líneas repetidas. Si también desea que el terminal esté conectado, deberá ser más elegante:

{ echo "$var"; cat - ; } | command

( echo "$var"; cat -   ) | command

Esto significa que la (s) primera (s) línea (s) serán el contenido de $varpero el resto provendrá de catleer su entrada estándar. Si el comando no hace nada demasiado sofisticado (intente activar la edición de la línea de comandos o ejecutarlo como lo vimhace), estará bien. De lo contrario, debe ser realmente elegante, creo que expectes probable que uno de sus derivados sea apropiado.

Las notaciones de la línea de comando son prácticamente idénticas, pero el segundo punto y coma es necesario con las llaves, mientras que no lo es con los paréntesis.


( echo "$LIST"; cat - ) | sed 1qesto funciona para mí pero necesito presionar ctrl d cuando ejecuto este script?
Gert Cuykens

Si; la cat -continúa para leer desde el teclado hasta que EOF o interrupción, por lo que necesita para contarlo EOF mediante la tipificación de control-D.
Jonathan Leffler

¿Hay alguna forma de evitar EOF? sed necesita gato
Gert Cuykens

No tiene que usar catnada si no desea una entrada de terminal, como en la primera línea. O puede usar catpara listar un archivo. O ... Si desea que el comando lea la entrada del terminal, debe informarle cuando haya llegado al final de la entrada. O podrías usar ( echo "$var"; sed /quit/q - ) | command; esto continúa hasta que escriba una línea que contenga 'salir'. Puede ser infinitamente inventivo con la forma en que lo maneja. Cuidado con la vieja leyenda urbana de un programa que dejó de funcionar cuando los usuarios empezaron a trabajar con Ecuador. Tecleaban el nombre de la capital, Quito, y el programa terminaba.
Jonathan Leffler

Bien si tú lo dices. ¿Pero por qué no solo echo "$LIST" | sed 1q | ...? Todo depende de lo que se trate. La <<EOFnotación debería requerir un EOF al comienzo de una línea por sí solo en algún lugar del archivo. No lo usaría, creo, pero todavía no estoy seguro de lo que está tratando de lograr. Un simple echo "$LIST" | commando echo $LIST | commandprobablemente será suficiente en la práctica (y es importante que conozca el significado de la diferencia entre los dos).
Jonathan Leffler

16

Me gustó la respuesta de Martin, pero tiene algunos problemas dependiendo de lo que haya en la variable. Esta

your-command <<< """$your_variable"""

es mejor si la variable contiene "o!


4
¿Pero por qué? Además, no puedo reproducir ningún problema: foo1=-; foo2='"'; foo3=\!; cat<<<"$foo1"; cat<<<"$foo2"; cat<<<"$foo3"funciona bien para mí. ¿Qué hacen exactamente los tres "? AFAIK, solo está anteponiendo y agregando una cadena vacía.
phk

Prueba algo real. Como si tu comando fuera ssh somehost. y su variable es un script de shell.
Robert Jacobs

16
(cat <<END
$passwd
END
) | command

El catno es realmente necesario, pero ayuda a estructurar el código mejor y le permite usar más comandos paréntesis como entrada a su comando.


Pero este método le permite pasar varias líneas a su comando y también permite espacios en el$passwd
PoltoS

4
Esta es la mejor respuesta hasta ahora que no filtra contenidos variables a la tubería o al proceso de indagación.
user2688272

8

Según la respuesta de Martin, hay una función de bash llamada Here Strings (que en sí misma es una variante de la función Here Documents más ampliamente compatible ).

http://www.gnu.org/software/bash/manual/bashref.html#Here-Strings

3.6.7 Aquí cadenas

Una variante de estos documentos, el formato es:

<<< word

La palabra se expande y se suministra al comando en su entrada estándar.

Tenga en cuenta que Here Strings parecería ser solo bash, por lo que, para una mejor portabilidad, probablemente estaría mejor con la función Here Documents original, según la respuesta de PoltoS:

( cat <<EOF
$variable
EOF
) | cmd

O una variante más simple de lo anterior:

(cmd <<EOF
$variable
EOF
)

Puede omitir (y ), a menos que desee que esto se redirija más a otros comandos.


5

Esta forma robusta y portátil ya ha aparecido en los comentarios. Debería ser una respuesta independiente.

printf '%s' "$var" | my_cmd

o

printf '%s\n' "$var" | my_cmd

Notas:

  • Es mejor que echo, las razones están aquí: ¿Por qué es printfmejor que echo?
  • printf "$var"Está Mal. El primer argumento es el formato donde se interpretan%s o gustan varias secuencias . Para pasar la variable correctamente, no debe interpretarse como formato.\n
  • Por lo general, las variables no contienen nuevas líneas finales. El primer comando (con %s) pasa la variable tal como está. Sin embargo, las herramientas que funcionan con texto pueden ignorar o quejarse de una línea incompleta (consulte ¿Por qué los archivos de texto deben terminar con una nueva línea? ). Por lo tanto, es posible que desee el último comando (con %s\n) que agrega un carácter de nueva línea al contenido de la variable. Hechos no obvios:

    • Aquí la cadena en Bash ( <<<"$var" my_cmd) agrega una nueva línea.
    • Cualquier método que agregue una nueva línea da como resultado un stdin de no vacío my_cmd, incluso si la variable está vacía o no está definida.

4

Prueba esto:

echo "$variable" | command

pero, ¿no aparecería la variable $ de contenido en, por ejemplo, la salida de ps -ucuando se está ejecutando echo?

2
no, no lo hará. echoes una función incorporada, por lo que no hay ningún proceso para mostrar en ps
unbeli

2
Cuidado con los espacios en tu variable: echo "$variable"es mejor.
Jonathan Leffler

así es, bash comerá espacios dobles, las conchas más inteligentes no lo harán
unbeli

-1

Solo haz:

printf "$my_var" | my_cmd

Si la var no contiene espacios, las comillas pueden omitirse.
Si usa bash, también puede hacer:

echo -n "$my_var" | my_cmd

Evite el uso de echo sin -n porque canalizará la variable con un salto de línea adicional al final.


1
no funciona si $ my_var es %s, printf no imprimirá nada. my_var="%s"; printf "$my_var"; - ¿Quizás intentarlo printf "%s" "$my_var" | my_cmd ?
hanshenrik
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.