Como passar argumentos para um subshell em -exec
Com find
do -exec
, você pode passar comandos complexos usando um subshell, conforme identificado corretamente. No entanto, existem alguns problemas com sua abordagem.
Sua variável externa $CHK
não será expandida, pois está entre aspas simples. O que você pode fazer para que o subshell saiba que esta variável é export
antes:
$ foo=bar
$ find . -type f -exec sh -c 'echo "$foo"' \;
(returns an empty line for every file found)
$ export foo=bar
$ find . -type f -exec sh -c 'echo "$foo"' \;
(returns "bar" for every file found)
Exportar uma variável faz com que ela faça parte do seu ambiente, que as subshells podem ler. Ou você passa isso como um argumento separado para o subshell, que é o caminho a seguir aqui:
$ foo=bar
$ find . -type f -exec sh -c 'echo "$0"' "$foo" \;
(returns "bar" for every file found)
Claro, você pode continuar com $1
, $2
etc e usar {}
como um argumento para seu subshell, também, para usar o nome do arquivo real. E não se esqueça de citar suas variáveis.
Seu caso específico
Você pode simplesmente reescrever seu comando em:
shasum -a512 * > "$CHK_OUTPUT"
porque shasum
é inteligente o suficiente para fazer o trabalho em um comando, lendo vários arquivos, sem um loop ou find
. Por padrão, *
não inclui arquivos que começam com um ponto (mas você pode alterá-lo com shopt -s dotglob
), portanto, as opções find
são desnecessárias, especialmente quando maxdepth
é 1.
Mas vamos fingir que shasum
não foi tão inteligente, então eu posso te dar mais algumas opções. Se você quiser usar find
, é assim que você lida com vários argumentos:
CHK='shasum -a512'
find ./ -type f ! -name ".*" -maxdepth 1 -exec \
sh -c '$0 "$(basename "$1")"' "$CHK" {} \; > "$CHK_OUTPUT"
Mas, mesmo assim, tudo isso também pode ser reescrito como mais legível:
today=$(date +%Y-%m-%d)
for f in *; do shasum -a512 "$f" > "($today)-checksum.txt"; done
Geralmente, é mais fácil percorrer os arquivos do que usar find
, embora haja um limite de quantos arquivos você pode processar dessa forma devido à expansão do *
. Em algum momento, será muito longo para você linha de comando (o limite específico depende do seu SO e shell).
E, claro, você pode fazer isso de forma recursiva com shopt -s globstar
no Bash ≥ 4.0:
shopt -s globstar
for f in **/*; do …; done
Mas isso novamente é o mesmo que:
shasum -a512 **/* > "$CHK_OUTPUT"