La página del manual para GNU find states:
-exec command ; [...] The string `{}' is replaced by the current file name being processed everywhere it occurs in the arguments to the command, not just in arguments where it is alone, as in some versions of find. Both of these constructions might need to be escaped (with a `\') or quoted to protect them from expansion by the shell.
Eso es del hombre a find
(GNU findutils) 4.4.2.
Ahora probé esto con bash y dash, y no es necesario que ambos {}
estén enmascarados. Aquí hay una prueba simple:
find /etc -name "hosts" -exec md5sum {} \;
¿Hay un caparazón, para el cual realmente necesito enmascarar los frenos? Tenga en cuenta que no depende de si el archivo encontrado contiene un espacio en blanco (invocado desde bash):
find ~ -maxdepth 1 -type d -name "U*" -exec ls -d {} \;
/home/stefan/Ubuntu One
Esto cambia si el archivo encontrado se pasa a una subshell:
find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d {}' \;
ls: cannot access /home/stefan/Ubuntu: No such file or directory
ls: cannot access One: No such file or directory
que puede resolverse mediante:
find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "$0"' {} \;
en contraste con:
find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "{}"' \;
/home/stefan/Ubuntu One
pero eso no es de lo que habla la página man, ¿verdad? Entonces, ¿qué shell trata {}
de una manera diferente?
Respuestas:
Resumen : si alguna vez hubo un shell que se expandió
{}
, es un legado realmente antiguo por ahora.En el shell Bourne y en los shells compatibles con POSIX, los corchetes (
{
y}
) son caracteres ordinarios (a diferencia de(
y)
que son delimitadores de palabras como;
y&
, y[
y]
que son caracteres globales). Se supone que las siguientes cadenas deben imprimirse literalmente:Una palabra que consiste en una sola llave es una palabra reservada , que solo es especial si es la primera palabra de un comando.
Ksh implementa la expansión de llaves como una extensión incompatible al shell Bourne. Esto se puede desactivar con
set +B
. Bash emula ksh a este respecto. Zsh también implementa la expansión de llaves; allí se puede apagar conset +I
osetopt ignore_braces
oemulate sh
. Ninguno de estos shells se expande{}
en ningún caso, incluso cuando es una subcadena de una palabra (pfoo{}bar
. Ej. ), Debido al uso común en argumentos parafind
yxargs
.Single Unix v2 señala que
Esta nota se eliminó en versiones posteriores del estándar; los ejemplos para
find
tienen usos sin comillas de{}
, al igual que los ejemplos paraxargs
. Puede haber habido conchas históricas de Bourne donde{}
debían citarse, pero ahora serían sistemas heredados realmente antiguos.Las implementaciones de CSH que tengo a la mano (OpenBSD 4.7, CSH BSD en Debian , tcsh) todo se expanden
{foo}
afoo
pero dejan{}
solo.fuente
bash
(ver$BASH_VERSION
). La expansión de llaves está muy viva y bien.{}
sintaxis se originó encsh
, pero se{}
expandió a la cadena vacía. Los proyectiles más nuevos reconocen que eso no tiene sentido, pero todavía hay algunos viejoscsh
.{}foo
se expandiría afoo
, pero{}
se expandiría a{}
(excepto cuando esté dentro de los backticks, pero las citas no ayudarían) y se documentó como tal. Lo verifiqué para el csh de 2BSD (primer lanzamiento), 2.79BSD, 2.8BSD y 2.11BSD.El
{}
necesitaba ser citado en versiones de lafish
cáscara antes de 3.0.0.Y en el shell rc (también
akanga
basado enrc
, pero noes
):Es probable que esos no sean los shells que los autores de esa documentación de GNU tenían en mente cuando escribieron ese texto desde que
fish
se lanzó por primera vez en 2005 (mientras que ese texto o similar ya estaba allí en 1994) yrc
originalmente no era un shell de Unix.Hay algunos rumores de que algunas versiones de
csh
(el shell que introdujo la expansión de llaves) lo requieren. Pero es difícil darles crédito a ellos ya que el primer lanzamiento decsh
2BSD no lo hizo. Aquí, como se probó en un emulador PDP11:Y la página del manual de 2BSD
csh
dice claramente :Por lo tanto, me resultaría muy extraño si una versión posterior de csh o tcsh lo rompiera más tarde.
Podría haber sido evitar algunos errores en algunas versiones. Aún con ese 2BSD csh (eso es lo mismo en 2.79BSD, 2.8BSD, 2.11BSD):
Sin embargo, las citas no ayudan:
Podría citar toda la sustitución del comando:
Pero eso es pasar un argumento a ese eco externo.
En
csh
otcsh
, debe citar el{}
cuando no está solo, como en:(aunque ese tipo de
find
uso no es portátil ya que algunosfind
s solo se expanden{}
por sí solos).fuente
En una palabra,
csh
.bash
y otros shells modernos reconocen que el usuario probablemente no está solicitando una expansión de llaves nulas. (Moderncsh
es en realidadtcsh
y ahora también puede manejarlo{}
sensualmente)fuente
csh
. No todos ejecutan utilidades GNU en Linux; de hecho, es bastante común instalarlos en sistemas comerciales Unix más antiguos cuyos comandos agrupados son limitados. (Reemplazarcsh
esos sistemas es menos probable, porque los scripts del sistema pueden depender de las idiosincrasias del originalcsh
, e incluso si todos los usuarios estuvieran configurados para usar uno más nuevocsh
,root
casi seguramente necesitarían seguir siendo la versión incluida.)pdksh
hace lo correcto ... aunque la respuesta correcta a eso es probablemente "realksh
es FOSS en estos días"...
para ksh93, bash y zsh). Sólo se expande (t) csh{foo}
afoo
, e incluso deja{}
solo (al menos en BSD de reciente).