GNU/Linux >> Tutoriales Linux >  >> Ubuntu

¿Cómo sabe un comando (es decir, Grep) cuándo se ejecuta como parte de la expansión Glob?

Según tengo entendido, el shell interpreta un comodín glob, que luego ejecuta el comando dado para cada nombre de archivo coincidente. Supongamos que tengo archivos:abc1, abc2, and abc3 en mi directorio actual. Entonces, por ejemplo, echo abc* se repetirá una vez por cada nombre de archivo que comience con 'abc'.

Sin embargo, si ejecuto grep 'foo' abc* , me imagino que esto debería ejecutarse:

grep 'foo' abc1
grep 'foo' abc2
grep 'foo' abc3

Lo que significa que debería obtener el siguiente resultado (suponiendo que todos los archivos contengan una línea que diga "foo"):

foo
foo
foo

Sin embargo, en su lugar obtengo:

abc1:foo
abc2:foo
abc3:foo

Así que me imagino que hay 2 posibles explicaciones para esto. Primero, de alguna manera grep puede detectar que se usó con expresiones globales y responde mostrando los nombres de archivo antes de las coincidencias. En segundo lugar, dado que puede pasar varios archivos a grep, el shell en realidad ejecuta solo 1 comando:

grep 'foo' abc1 abc2 abc3

Sin embargo, esto solo funciona porque grep acepta múltiples archivos al final. Es posible que otro comando solo permita pasar 1 archivo. Por lo tanto, si quisiera ejecutar el comando para varios archivos que coincidan con el glob, no funcionaría si globbing funcionara a través del segundo método descrito anteriormente.

De todos modos, ¿alguien puede arrojar algo de luz sobre esto?

¡Gracias!

Respuesta aceptada:

Ese es el truco:el comando no sabe, es el shell el que hace el trabajo

Considere, por ejemplo, grep 'abc' *.txt . Si ejecutamos un seguimiento de las llamadas al sistema, verá algo como esto:

bash-4.3$ strace -e trace=execve grep "abc" *.txt > /dev/null
execve("/bin/grep", ["grep", "abc", "ADDA_converters.txt", "after.txt", "altera_license.txt", "altera.txt", "ANALOG_DIGITAL_NOTES.txt", "androiddev.txt", "answer2.txt", "answer.txt", "ANSWER.txt", "ascii.txt", "askubuntu-profile.txt", "AskUbuntu_Translators.txt", "a.txt", "bash_result.txt", ...], [/* 80 vars */]) = 0
+++ exited with 0 +++

El shell expandió *.txt en todos los nombres de archivo en el directorio actual que terminan con .txt extensión. De manera tan efectiva, su shell traduce el grep 'abc' *.txt comando en grep 'abc' file1.txt file2.txt file3.txt . . . . Por lo tanto, su segunda suposición es correcta.

La primera suposición no es correcta:los programas no tienen forma de detectar glob. Es posible pasar * como argumento de cadena para el comando, pero es el trabajo del comando decidir qué hacer con él en ese momento. La expansión del nombre de archivo, sin embargo, es propiedad de su shell respectivo como ya he mencionado.

Sin embargo, esto solo funciona porque grep acepta múltiples archivos al final. Es posible que otro comando solo permita pasar 1 archivo.

Exactamente correcto ! Los programas no limitan la cantidad de argumentos de línea de comandos aceptables (por ejemplo, en C, esa es una matriz de cadenas const char *args[] y en python sys.argv[] ), pero pueden detectar la longitud de esa matriz o si algo inesperado está o no en la posición incorrecta de la matriz. grep no hace eso y acepta múltiples archivos, lo cual es por diseño.

Relacionado:Después de actualizar a Ubuntu 13.10, ¿Firefox a veces bloquea la computadora?

En la nota al margen, las citas incorrectas junto con el globbing con grep a veces pueden ser un problema. Considere esto:

bash-4.3$ echo "one two" | strace -e trace=execve grep *est*
execve("/bin/grep", ["grep", "self_test.sh", "test.wxg"], [/* 80 vars */]) = 0
+++ exited with 1 +++

El usuario no preparado esperaría que grep coincida con cualquier línea con est las letras en él provienen de la tubería, pero en cambio, la expansión del nombre de archivo de Shell lo torció todo. He visto que esto sucede mucho con personas que hacen ps aux | grep shell_script_name.sh , y esperan encontrar su proceso ejecutándose, pero porque ejecutaron el comando desde mismo directorio donde estaba el script , la expansión del nombre de archivo de shell se hizo grep comando para lucir detrás de escena completamente diferente de lo que el usuario esperaba.

La forma correcta sería usar comillas simples:

bash-4.3$ echo "one two" | strace -e trace=execve grep '*est*'
execve("/bin/grep", ["grep", "*est*"], [/* 80 vars */]) = 0
+++ exited with 1 +++

Ubuntu
  1. Cómo usar el comando grep de Linux

  2. ¿Cómo ejecutamos un comando almacenado en una variable?

  3. ¿Cómo ejecutar el comando original que tiene un alias con el mismo nombre?

  4. ¿Cómo ejecutar la aplicación durante un tiempo determinado en Shell?

  5. ¿Cómo asegurar que Wine no ejecute automáticamente los archivos .exe?

CÓMO UTILIZAR EL COMANDO DE COLA

Cómo usar el comando principal

Cómo usar grep en Linux

Cómo administrar Snaps en Linux - Parte 2

¿Qué hace el comando Startx?

¿Qué es el comando Grep en Linux? ¿Por qué se usa y cómo funciona?