¿Cómo puedo enviar caracteres a un comando como si vinieran de un archivo?

22

¿Cómo puedo enviar caracteres a un comando como si vinieran de un archivo?

Por ejemplo probé:

wc < "apple pear orange"
-bash: apple pear orange: No such file or directory
Tyler Durden
fuente

Respuestas:

32

En los shells que admiten cadenas aquí , incluidos bash, zshy ksh93, puede usar

wc <<< "apple pear orange"
conductor de acero
fuente
@Kusalananda gracias - Edité tu información en
steeldriver el
18

Otros dos enfoques (que permiten la entrada de varias líneas sin esfuerzo adicional):

  1. Use un "documento aquí":

    $ wc << EOF
    manzana pera naranja
    EOF
      1 3 18
    PS

    La EOFcadena es un delimitador. Puedes usar cualquier cadena; EOFEs solo una elección convencional.

  2. Use el tty como entrada:

    $ wc
    manzana pera naranja
    Ctrl+D
      1 3 18
    PS

    Esto tiene el inconveniente de que el programa comienza a ejecutarse y comienza a leer la entrada, tan pronto como escribe su nombre. Esto puede ser desconcertante; por ejemplo:

    $ grep v
    El zorro marrón rápido              (mecanografiado) 
    salta                       (mecanografía) 
    salta                       (¡Esto es resultado de grep!) 
    El perro perezoso.                   (escrito)
    Ctrl + D
                                    (Sin salida aquí) 
    $
G-Man dice 'restablecer a Monica'
fuente
Para el registro: el <<<formulario también permite la entrada de varias líneas sin esfuerzo adicional, ya que la "cadena cerrada puede contener nuevas líneas. Por supuesto, el << EOFformulario (la sintaxis original del documento aquí) es más fácil de leer si tiene una entrada de varias líneas.
alexis
La página de manual dice que aquí la sintaxis de cadena es <<< word, por supuesto, en el contexto del shell, a wordpuede ser una cadena entre comillas, que contiene espacios y líneas nuevas. D'oh! Eso es tan obvio que no hace falta decirlo (y, de hecho, no lo veo mencionado en la página del manual). :-( ¡Gracias por señalarme esto!
G-Man dice 'Reinstate Monica' el
No lo llamaría simple u obvio, de verdad. A wordse define en la página de manual como "Una secuencia de caracteres considerados como una sola unidad por el shell" (también conocido como "token"), y debe saber que las cadenas entre comillas se tratan como "una sola unidad" en el sentido relevante (después de procesamiento de barra diagonal inversa, expansión variable, etc. "Pero, de hecho, ese es el propósito de las comillas dobles en el shell. (Las comillas simples también protegen de la expansión). El modelo de procesamiento del shell está muy bien pensado, y todo menos simple.
alexis
@alexis: cuando me excedo de esa manera e incluyo un emoticón, uno debería considerar la posibilidad de que sea irónico.
G-Man dice 'Reincorporar a Monica'
10

Aunque hay varias soluciones válidas aquí, otra sintaxis que a veces puede ser útil es ejecutar un comando <(). Esto le permitiría crear más de 1 objeto descriptor de archivo en una línea de comando.

Esto puede ser útil cuando está haciendo algo como comparar largas cadenas de texto, o si desea diferir parte del contenido que no está en un archivo.

Por ejemplo, comparando los archivos hosts en dos nodos sin tener que copiar el archivo hosts en el host local:

diff -Naur <(cat /etc/hosts) <(ssh -q otherhost 'cat /etc/hosts')

El <redirige a un archivo STDIN, y el ()crear un subnivel para ejecutar el comando entre paréntesis. Es el STDOUT del subshell que se pasa a STDIN del comando que se está ejecutando.

Es una manera más fácil de crear más de 1 "archivo" de entrada para un comando que tratar de usar múltiples documentos aquí, o intentar hacer eco de múltiples comandos en una tubería al comando final.

Tim Kennedy
fuente
<fileorpathnameredirige stdin, pero <(subcmd)no lo hace; sustituye un nombre que cuando / si el programa lo abre puede leer stdout desde subcmd. < <(subcmd)(espacio requerido) redirige stdin desde ese archivo, casi como subcmd |. Su diffpodía leer una de sus entradas a partir de la entrada estándar mediante la especificación de un argumento de -, pero no ambos.
dave_thompson_085
Esa es la sustitución del proceso que no es compatible, a diferencia de las partes que dice que está hecha (pero no es como lo explicó Dave).
phk
1
Mi diff funciona bien en bash en los sistemas Ubuntu 16.04 y Solaris 11.2 con los que tengo que probar. Es posible que no funcione para todos los shells en todos los sistemas operativos. En realidad, está creando descriptores de archivo que pueden usarse para leer la salida del subproceso como si estuviera leyendo un archivo. Dado que diff toma dos argumentos de archivo, puede leer la salida de ambos subprocesos a través de los descriptores de archivo creados y compararlos.
Tim Kennedy el
Es posible que desee agregar a su respuesta la diferencia entre cmd <(cmd2 ...)y cmd < <(cmd2 ...). El primero permite que los datos derivados (la salida de cmd2) se usen en lugar de un nombre de archivo. Este último es equivalente a cmd2 ... | cmd. Los comandos deben escribirse para aceptar explícitamente la entrada stdin y muchos no lo son. Esto es especialmente cierto para los scripts de shell.
DocSalvager
8

puedes usar una pipa

echo "apple pear orange" | wc
Slh47
fuente
8
Una tubería no es lo mismo que "leer de un archivo". Por ejemplo, no puede buscar hacia atrás en una tubería, mientras que puede hacerlo en un archivo.
rbialon
0

Es posible que desee utilizar algo similar a lo esperado. El siguiente es un ejemplo simple de abrir una sesión remota de telnet, esperar el aviso, enviar algunos datos, esperar una respuesta, dormir y salir.

#!/usr/bin/expect
spawn telnet localhost 8555
expect "Escape character is '^]'."
send "Hello World\n"
expect "Connection closed by foreign host."
sleep 1
Cobarde anónimo
fuente