2009-10-01 11 views
6

considerar:tuberías, argumentos de entrada y la línea de comandos estándar de Bash

command1 | command2 

es la salida de comando1 utiliza como entrada estándar de comando2 o como argumentos de línea de comando para command2?

Por ejemplo,

cat test.sh | grep "hehe" 

¿Cuál es su forma equivalente sin necesidad de utilizar un tubo?

me trataron

grep "hehe" $(cat test.sh) 

y parece no ser correcta.

+1

Su pregunta es un poco confusa, con suerte ya sea que ingrese la redirección o simplemente proporcione el nombre de archivo como argumento es lo que quería. Por otro lado, si está preguntando cómo tomar la salida estándar de un comando y darle al stdin de otro comando sin usar un tubo ... esa es la definición de un tubo. – Cascabel

Respuesta

14
grep "hehe" < test.sh 

redirección de entrada - que funciona para un solo archivo, por supuesto, mientras cat funciona para cualquier número de archivos de entrada.


Considerar las notaciones:

grep "hehe" $(cat test.sh) 
grep "hehe" `cat test.sh` 

Estos son equivalentes en este contexto; es mucho más fácil utilizar el '$(cmd)' notación en usos anidados, tales como:

x=$(dirname $(dirname $(which gcc))) 
x=`dirname \`dirname \\\`which gcc\\\`\`` 

(Esto le da el directorio base en la que está instalado GCC, en caso de que se está preguntando.)

En el ejemplo grep, lo que ocurre es que el contenido de test.sh se lee y se divide en palabras separadas en espacios en blanco, y cada palabra se proporciona como argumento en grep. Como grep trata las palabras después de "hehe" (donde grep, por supuesto, no ver las comillas dobles - y no son necesarias en este caso; como regla general, utilice comillas simples en lugar de comillas dobles, especialmente en cadenas complejas como expresiones regulares que a menudo usan metacaracteres de shell) ... Como estaba diciendo, grep trata las palabras después de "hehe" como nombres de archivo, e intenta abrir cada archivo, generalmente fracasando tristemente porque los archivos no existen. Esta es la razón por la cual la notación no es apropiada en este contexto.


Después de volver a consultar la pregunta, hay más que decir, eso no se ha dicho.

En primer lugar, muchos comandos de Unix están diseñados para funcionar como 'filtros'; leen la entrada de algunos archivos, la transforman de alguna forma y escriben el resultado en la salida estándar. Tales comandos están diseñados para su uso dentro de tuberías de comando. Los ejemplos incluyen:

  • gato
  • grep
  • troff y familiares
  • awk (con salvedades)
  • sed
  • tipo

Todos estos filtros tienen el mismo comportamiento general : toman opciones de línea de comando para controlar su comportamiento, y luego leen el archivo s especificado como argumentos de línea de comando o, si no hay tales argumentos, leen su entrada estándar. Algunos (como sort) pueden tener opciones para controlar a dónde va su salida en lugar de la salida estándar, pero eso es relativamente poco común.

Hay algunos filtros puros: tr es uno de esos, que lee estrictamente la entrada estándar y escribe en la salida estándar.

Otros comandos tienen comportamientos diferentes. Eric Raymond proporciona una taxonomía para los tipos de comando en "The Art of UNIX Programming".

Algunos comandos generan listas de nombres de archivo en salida estándar; los dos clásicos son ls y find.

A veces, desea aplicar la salida de un generador de nombre de archivo como argumentos de línea de comando para un filtro. Hay un programa que lo hace automáticamente: es xargs.

Clásicamente, se debería utilizar:

find . -name '*.[chyl]' | xargs grep -n magic_name /dev/null 

Esto generaría una lista completa de archivos con '.c', '.h', '.y' y '.l' (fuente C, encabezados de las extensiones, Yacc y archivos Lex). Como la lista se lee por xargs, creará líneas de comando con grep -n magic_name /dev/null al comienzo y cada palabra (separada por espacios en blanco) como argumento.

En los viejos tiempos, los nombres de archivo Unix no incluían espacios. Bajo la influencia de Mac y Windows, estos espacios ahora son un lugar común. Las versiones GNU de find y xargs tienen opciones complementarias para hacer frente a este problema:

find . -name '*.[chyl]' -print0 | xargs -0 grep -n magic_name /dev/null 

La opción '-print0' significa "nombres de archivo de impresión terminados por un NUL '\ 0'" (porque los únicos personajes que pueden no aparecer en un nombre de archivo (simple) son '/' y NUL, y obviamente, '/' puede aparecer en nombres de ruta). El '-0' correspondiente dice xargs para buscar nombres terminados por NUL en lugar de nombres separados por espacios.

+0

¿La redirección de entrada proporciona entrada estándar o argumento de línea de comando a grep? – Tim

+0

En realidad, mi pregunta es para un comando más general que solo para grep. – Tim

+0

Entonces veo, después de limpiarlo ... y he generalizado mi respuesta: D –

1

Se usa como stdin.

Probar:

grep "hehe" - $(cat test.sh) 

que podría estar equivocado; No puedo probarlo en esta computadora. Si lo hace sin el tubo como lo intentó, grep trata el último argumento como un nombre de archivo, es decir, busca un archivo llamado [contenido de test.sh]. Si lo pasa a - (o no pone un último argumento), le dice que use stdin como el archivo.

También se puede simplemente pasar grep un archivo para escanear a través de:

grep "hehe" test.sh 

... pero parece estar pidiendo más de una pregunta fiesta generalizada, no es realmente una cuestión de uso grep, por lo que probablemente no es muy útil.

+0

Toma cada palabra en test.sh y busca un archivo con el mismo nombre que esa palabra, y greps en esos archivos (generalmente con un éxito muy limitado). –

+0

Los backticks son sustitución de comandos como '$()', simplemente no encajables y más fáciles de estropear. La última forma es probablemente lo que Tim está buscando. – Cascabel

+0

Me di cuenta de eso; Ya estaba editando. : P –

6

Otra forma de redirección es la sustitución de procesos.

grep "hehe" <(cat test.sh) 

es equivalente a:

grep "hehe" test.sh 

la que ambos mirada a los contenidos de test.sh sí.

Si bien, como se ha señalado, este comando:

grep "hehe" $(cat test.sh) 

se buscan nombres de archivo en test.sh y los utiliza como argumentos para grep. Así que si test.sh consiste en:

scriptone 
scripttwo 

continuación grep va a buscar "jeje" en los contenidos de cada uno de esos archivos.

+2

No me gusta su uso de 'es equivalente' en la línea 3: 'grep' jeje 'test.sh' es, en última instancia, utilizando los contenidos de test.sh como stdin mientras que 'grep" jeje "<(prueba de gato. sh) 'está usando la salida del comando' cat test.sh' como stdin. Considere la diferencia en los resultados si ejecuta los comandos de la siguiente manera: 'grep -H" jeje "<(cat test.sh)' y 'grep -H" jeje "test.sh' –

1

¿Cuál es el equivalente de una tubería bash usando argumentos de línea de comando?

Las tuberías y los argumentos de línea de comandos son formas diferentes de entrada que no son intercambiables. Si un programa le permite tener formas equivalentes de ambos, esa es la elección de ese programa solo. (En el código fuente, los argumentos de la línea de comando aparecen como texto en una variable, mientras que los pipes aparecen como archivos abiertos, incluidos stdin y stdout. Sintaxis de redirección de E/S de Bash, como se usa aquí más adelante, técnicamente no no pertenecen a los argumentos de línea de comando, a pesar de que por escrito al lado de ellos en la línea de comandos ...)

Pero vamos a ser pedante y también responder a esta:

¿Cuál es el equivalente de una tubería de fiesta sin utilizar un carácter de barra vertical fiesta?

Respuesta: cat test.sh | grep "hehe" es equivalente a

grep "hehe" < <(cat test.sh) 

Explicación:

  • Tubos redirigir la salida estándar de un comando a la entrada estándar de otro. Para establecer la fuente de stdin, podemos usar la redirección de entrada (< …) en lugar de usar el carácter de tubería.
  • Sin embargo, sólo el uso de redirección de entrada (grep "hehe" < test.sh) no es el equivalente a las tuberías, ya que utiliza un archivo como la fuente de la entrada estándar, mientras que los tubos utilizan la salida de un comando (cat test.sh). Por lo tanto, además, agregamos la sustitución de proceso <(…) para reemplazar la entrada de un archivo con la entrada de un comando.
  • Por supuesto, el ejemplo es confuso porque las dos variantes tienen los mismos efectos:

    grep "hehe" < test.sh 
    grep "hehe" < <(cat test.sh) 
    

    Pero técnicamente, entrada desde un archivo sigue siendo un mecanismo diferente al de entrada de la salida de un comando que obtiene su entrada de un archivo.

Fuente: Advanced Bash Scripting Manual, section on process substitution (comenzar a leer en "Algunos otros usos").

Cuestiones relacionadas