Eu tenho um script bash existente que chamo assim:
find /path/to/my/stuff -type d -exec sh -c 'cd "$0"; /path/to/my/script.sh function_name fn_parameter' {} \;
Eu mudo frequentemente o /path/to/my/stuff
and fn_parameter
. Eu também preciso às vezes mudar o function_name
.
Está ficando tedioso continuar digitando esse comando, então gostaria de envolvê-lo em outro script e passar apenas esses três parâmetros assim:
wrapper.sh function_name "/path/to/my/stuff" fn_parameter
Nota lateral: alterei a ordem dos argumentos porque "function_name" é o que muda com menos frequência.
Estou ficando sobrecarregado citando e escapando quando tento fazer esse script wrapper. Eu olhei para o script em shellcheck.net e também tentei usar uma matriz para cmd
(consulte uma das minhas tentativas fracassadas abaixo) sem sucesso. Eu entendo que o problema é mais provável que aspas e barras invertidas não estejam sendo respeitadas, mas não consigo entender como resolver isso.
Esta é uma das minhas muitas tentativas fracassadas:
wrapper.sh
#!/bin/bash
function_name=$1
mpath="$2"
arg=$3
find "$mpath" -type d -exec sh -c "cd \"$0\"; /path/to/my/script.sh $function_name $arg" {} \;
Aqui está outro exemplo de uma tentativa fracassada:
#!/bin/bash
function_name=$1
mpath="$2"
arg=$3
cmd="'cd \$0; /path/to/my/script.sh $function_name $arg'"
echo "find \"$mpath\" -type d -exec sh -c $cmd {} \;"
find "$mpath" -type d -exec sh -c $cmd {} \;
No exemplo acima, se eu inserir a saída da instrução echo na linha de comando, ela funcionará corretamente. Mas o wrapper falha com:
$0;: -c: line 1: unexpected EOF while looking for matching `''
$0;: -c: line 2: syntax error: unexpected end of file
Para completar, myscript.sh é semelhante a isto:
#!/bin/bash
fn1() {
...
}
fn2() {
...
}
fn3() {
...
}
"$@"
Duas variantes do seu código, cada uma passando os valores especiais para o script in-line que você chama de
find
:Quando um diretório é encontrado,
find
simplesmente passa os valores das duas variáveisfn_name
efn_arg
nosh -c
script como os dois primeiros argumentos, antes do argumento do caminho do diretório. Dentro do script, usamos os dois primeiros argumentos como argumentos para seu script e o terceiro como o caminho do diretório paracd
entrar.Observe que
$0
conterá a stringsh
. O shell usará essa string (arbitrária) em qualquer mensagem de erro que possa produzir (você mostra um exemplo disso em sua pergunta). O$0
valor não faz parte da lista de parâmetros posicionais.Outra variante que chama um script in-line com tantos caminhos de diretório quanto possível de uma só vez:
Alterando
\;
para+
no final dofind
comando, chamamos osh -c
com lotes de caminhos de diretório encontrados. O script in-line então precisa fazer um loop sobre eles e chamar seu script para cada um deles.O script in-line começa selecionando o nome da função e o argumento da lista de parâmetros posicionais e os desloca dessa lista. Em seguida, ele percorre os argumentos e chamadas restantes
cd
e seu script em cada um. O seguinte é o script in-line com um pouco de ar extra inserido:Eu corro o corpo do loop em um sub-shell para evitar ter que "
cd
voltar" toda vez depois de executar seu script.Estou usando
sh
aqui em vez de não faltarbash
nadash
para executar esse código. Além disso, osfind
comandos mostrados aqui estão usando apenas recursos padrão.Aqui está minha solução proposta (e funcional):
Edit: Em resposta aos comentários, esta solução não funciona com caminhos relativos.