O Find não possui nenhum mecanismo de escape
Este fato não permitirá que você insira {}
dentro de uma opção -exec
e / ou -execdir
existente. A substituição é feita com strncpy()
simples. O exec
/ execdir
é executado dentro do GNU-find (que eu estou usando como referência) através de bc_push_arg
. Para o formulário {} +
, temos:
/* "+" terminator, so we can just append our arguments after the
* command and initial arguments.
*/
execp->replace_vec = NULL;
execp->ctl.replace_pat = NULL;
execp->ctl.rplen = 0;
execp->ctl.lines_per_exec = 0; /* no limit */
execp->ctl.args_per_exec = 0; /* no limit */
/* remember how many arguments there are */
execp->ctl.initial_argc = (end-start) - 1;
/* execp->state = xmalloc(sizeof struct buildcmd_state); */
bc_init_state (&execp->ctl, &execp->state, execp);
/* Gather the initial arguments. Skip the {}. */
for (i=start; i<end-1; ++i)
{
bc_push_arg (&execp->ctl, &execp->state,
argv[i], strlen (argv[i])+1,
NULL, 0,
1);
}
Ele acrescenta tudo no final, pois você não pode ter mais de uma instância de {}
no formulário {} +
. E para o {} ;
, temos:
/* Semicolon terminator - more than one {} is supported, so we
* have to do brace-replacement.
*/
execp->num_args = end - start;
execp->ctl.replace_pat = "{}";
execp->ctl.rplen = strlen (execp->ctl.replace_pat);
execp->ctl.lines_per_exec = 0; /* no limit */
execp->ctl.args_per_exec = 0; /* no limit */
execp->replace_vec = xmalloc (sizeof(char*)*execp->num_args);
/* execp->state = xmalloc(sizeof(*(execp->state))); */
bc_init_state (&execp->ctl, &execp->state, execp);
/* Remember the (pre-replacement) arguments for later. */
for (i=0; i<execp->num_args; ++i)
{
execp->replace_vec[i] = argv[i+start];
}
Portanto, temos execp->ctl.replace_pat = "{}";
. Isso é tudo em parser.c
O texto acima é substituído como:
size_t len; /* Length in ARG before 'replace_pat'. */
char *s = mbsstr (arg, ctl->replace_pat);
if (s)
{
len = s - arg;
}
else
{
len = arglen;
}
if (bytes_left <= len)
break;
else
bytes_left -= len;
strncpy (p, arg, len);
p += len;
arg += len;
arglen -= len;
Em bc_do_insert()
em buildcmd.c
.
Portanto, não, não há como escapar do {}
. No entanto, algumas versões do find não substituirão {}/foo
, mas apenas {}
, assim você poderá usar duas versões diferentes de find juntas com um -exec sh -c 'someCommad {}'
.
Assumindo que gfind
é o GNU-find e afind
é o AIX que você provavelmente consegue:
afind . -type d -execdir test -f foo.jpg \
-exec sh -c 'gfind . -name "*.m4a" -exec someCommand {} \;' \;
Mas isso seria um hack horrível.
Solução alternativa decente
O problema que você está enfrentando é que você está executando a globalização para obter todos os arquivos de um tipo em um diretório. Em outras palavras, você está primeiro encontrando um diretório e globbing todos os arquivos desse diretório para fazer parte de uma linha de comando única .
Este é o tipo de problema que -execdir
pretende resolver. Ele irá executar o comando no diretório que contém o arquivo encontrado. Por exemplo:
$ mkdir -p a/a b/b c/c d e
$ touch a/a/foo.m4a b/b/foo.m4a
$ touch a/a/bar.m4a b/b/bar.m4a c/c/foobar.m4a
$ touch a/a/yay.jpg c/c/yay.jpg
$ find . -type f -name '*.m4a' -execdir test -e yay.jpg \; \
-execdir echo someCommand --arg yay.jpg {} +
someCommand --arg yay.jpg ./foobar.m4a
someCommand --arg yay.jpg ./bar.m4a ./foo.m4a
Além disso, estou usando o formulário {} +
em vez do formulário {} ;
para o exec
. Isso colocará todos os arquivos encontrados (no diretório em que está sendo executado) na mesma linha de comando.
Observe que o comando não foi executado em b/b
porque o test -e
o impediu.