La elegante simplicidad de Bash parece perderse en su enorme página de manual.
Además de las excelentes soluciones anteriores, pensé que trataría de darle una hoja de trucos sobre cómo bash analiza e interpreta las declaraciones . Luego, utilizando esta hoja de ruta, analizaré los ejemplos presentados por el interrogador para ayudarlo a comprender mejor por qué no funcionan según lo previsto.
Nota: Las líneas de script de Shell se usan directamente. Las líneas de entrada escritas se expanden primero en la historia.
Cada línea bash se tokeniza primero o, en otras palabras, se corta en lo que se llaman tokens . (La tokenización ocurre antes de todas las demás expansiones, incluidas llaves, tildes, parámetros, comandos, aritmética, procesos, división de palabras y expansión de nombre de archivo).
Un token aquí significa una parte de la línea de entrada separada (delimitada) por uno de estos metacaracteres especiales:
space, - White space...
tab,
newline,
‘<’, - Redirection & piping...
‘|’,
‘>’
‘&’, - And/Both < | > | >> .or. &<file descriptor>
‘;’, - Command termination
‘(’, - Subshell, closed by - ‘)’
Bash usa muchos otros caracteres especiales, pero solo estos 10 producen los tokens iniciales.
Sin embargo, debido a que estos metacaracteres también a veces deben usarse dentro de un token, debe haber una forma de quitarles su significado especial. Esto se llama escapar. La fuga se realiza citando una cadena de uno o más caracteres (es decir,'xx..'
, "xx.."
), o prefijando un carácter individual con un back-slash, (es decir \x
). (Es un poco más complicado que esto porque las citas también necesitan ser citadas, y porque las comillas dobles no citan todo, pero esta simplificación servirá por ahora).
No confunda la cita de bash con la idea de citar una cadena de texto, como en otros idiomas. Lo que está entre comillas en bash no son cadenas, sino más bien secciones de la línea de entrada que tienen metacaracteres escapados para que no delimiten tokens.
Tenga en cuenta que hay una diferencia importante entre '
, y "
, pero eso es para otro día.
Los metacaracteres restantes sin escape se convierten en separadores de tokens.
Por ejemplo,
$ echo "x"'y'\g
xyg
$ echo "<"'|'\>
<|>
$ echo x\; echo y
x; echo y
En el primer ejemplo, hay dos tokens producidos por un delimitador de espacio: echo
y xyz
.
Del mismo modo en el segundo ejemplo.
En el tercer ejemplo, el punto y coma se escapó, por lo que hay 4 tokens producidos por un delimitador de espacio, echo
, x;
, echo
, y y
. El primer token se ejecuta como comando y toma los siguientes tres tokens como entrada. Tenga en cuenta que el segundo echo
no se ejecuta.
Lo importante a recordar es que las primeras miradas de bash para los personajes que escapan ( '
, "
y \
), y luego busca delimitadores meta-caracteres sin escape, en ese orden.
Si no se escapa, estos 10 caracteres especiales sirven como token
delimitadores. Algunos de ellos también tienen un significado adicional, pero ante todo, son delimitadores de fichas.
Que grep espera
En el ejemplo anterior grep necesita estos tokens, grep
, string
,filename
.
El primer intento de la pregunta fue:
$ grep (luego | allí) xx
En este caso (
, )
y |
son meta-caracteres sin escape y así sirven para dividir la entrada en estas fichas: grep
, (
, then
, |
, there
, )
, y x.x
. grep quiere ver grep
, then|there
yx.x
.
El segundo intento de la pregunta fue:
grep "(entonces | allí)" xx
Este tokenizes en grep
, (then|there)
, x.x
. Puede ver esto si cambia grep por echo:
echo "(entonces | allí)" xx
(luego | allí) xx