Separe o nome do arquivo e o caminho dentro da opção -exec do comando find

Separe o nome do arquivo e o caminho dentro da opção -exec do comando find

Estou lutando com a avaliação de escape e expressão. Estou tentando executar um comando dentro de uma estrutura find... , onde opera em um arquivo e gera saída para o stdout. Para usar isso normalmente na linha de comando, simplesmente redireciono para um novo arquivo, assim:-exec COMMANDCOMMANDCOMMAND

COMMAND inputfilename.md > outputfilename.md.conf

Isso funciona bem. No entanto, se eu quiser fazer um loop recursivoTODOSos arquivos em um diretório e seu subdiretório, usando find -exec, não consigo descobrir como separar o nome do arquivo e o caminho para poder redirecionar corretamente. Por exemplo, isso produz um erro:

find ./ *.md -not -path './/.git/*' -exec COMMAND '{} > ~/wiki/newdirectory/{}.cong' \;

porque {}expande todo o caminho do arquivo. Eu tentei várias combinações de basenameand dirname, mas não consigo avaliá-los (em vez disso, apenas recebo a string 'basename' etc.). Por exemplo, isso não funcionou, porque o texto 'basename' simplesmente aparece

find ./ *.md -not -path './/.git/*' -exec COMMAND  '{} > ~/wiki/newdirectory/''basename {}''.conf' \;

(retorna este erro:) 'No such file or directory - .//newdirectory/README.md.conf > ~/wiki/newdirectory/basename .//newdirectory/README.md.conf'.

Qualquer ajuda seria apreciada. Resumindo, o objetivo é:

  1. Iterar recursivamente todos os arquivos correspondentes *.mdem um diretório
  2. Execute COMMAND inputfile.md > ~/newdirectory/inputfile.md.confonde inputfileestá a mesma string em cada iteração.

Obrigado!

Responder1

Faça o que fizer, você precisará invocar um shell para realizar o redirecionamento da saída do comando para um arquivo cuja localização depende do findresultado.

find ./ *.md -not -path './/.git/*' -exec sh -c 'COMMAND "$0" > ~/wiki/newdirectory/"${0##*/}.cong"' {} \;

Não substitua {}dentro do shell script. Isto não é suportado em todos os sistemas, e mesmo onde é, isso não funcionaria em geral, uma vez que trataria o nome do arquivo como uma parte da sintaxe do shell, por exemplo, um arquivo chamado ;rm -rf ~;.mdfaria com que você apagasse todos os seus arquivos.

${0##*/}usa pura manipulação de string para obter o nome base do arquivo. Você também pode usar $(basename -- "$0").

Responder2

Se você findaceitar -execdir, isso deve funcionar

find . -name '*.md' -not -path './/.git/*' -execdir COMMAND {} > ~/wiki/newdirectory/{}.cong \;

Alternativamente

find . -name '*.md' -not -path './/.git/*' -exec bash -c \
'for f; do COMMAND "$f" > ~/wiki/newdirectory/"${f##*/}".cong; done' _ {} +

informação relacionada