Usando find, xargs, etc. para gerar arquivos com nomes semelhantes

2

Eu tenho uma pasta cheia de arquivos HTML:

001.htm
002.htm
003.htm
…

Eu quero rodar o Pandoc para convertê-los em arquivos Markdown de nome similar:

001.md
002.md
003.md

Este comando funciona em um deles:

pandoc -f html -t markdown 001.htm -o 001.md

E eu quero usar find e xargs para executar automaticamente um comando semelhante em todos os arquivos da pasta.

Cheguei até aqui:

find *.htm | xargs -I {} -n 1 pandoc -f html -t markdown -o {}

… O que trunca todos os arquivos no diretório, então agora estou perguntando antes de realmente quebrar alguma coisa.

O que está errado com o meu comando acima e / ou o que é uma maneira completamente diferente / mais eficiente de fazer isso?

75th Trombone
fonte

Respostas:

3

Eu consegui fazer isso com este 1 liner. Se você é flexível sobre o xargs e find parte.

for f in ./*.htm; do pandoc -f html -t markdown "$f" -o "${f%.htm}.md"; done

Se você quiser agir recursivamente (assim: todos .htm arquivos no diretório atual, e todos os subdiretórios), então (assumindo o bash 4+) você pode usar o globstar opção de shell:

shopt -s globstar
for f in ./**/*.htm; do pandoc -f html -t markdown "$f" -o "${f%.htm}.md"; done
Martín Canaval
fonte
2
+1. O xargs não permite a mesma flexibilidade de modificação de nome de arquivo. Faz não substituir *.htm com $(find...) - nomes de arquivos com espaços serão tratados corretamente no primeiro caso, mas não o segundo.
glenn jackman
1
@glennjackman A menos que você defina a festança $IFS para $'\n' para essa seção de código, em cujo caso os espaços não são um problema - as novas linhas ainda estão no entanto.
Daniel Beck
Uau, há duas ou três coisas novas sobre a linha de comando para eu aprender com esse trecho. Obrigado!
75th Trombone
3

Usando {} não é flexível o suficiente para algumas situações. Isso parece ser um desses.

Uma solução possível seria -exec um script de find, igual a:

find . -name '*.htm' -exec ./convert-to-md.sh {} \;

O arquivo de script deve ser semelhante a este, dependendo do exato pandoc linha de comando:

#!/bin/bash
pandoc -f html -t markdown -o "${1/.htm/.md}" "${1}"

Se você não quer criar e salvar um arquivo de script para isso, você sempre pode inline bash código de script:

find . -name '*.htm' | xargs -n 1 bash -c 'pandoc -f html -t markdown -o "${1/.htm/.md}" "${1}"' -

O adicional - no final serve para preencher $0 no bash, que geralmente inclui o nome do script de shell, argumentos posicionais a partir de $0.

Isso permite que você continue usando find (mesmo com -print0 e xargs -0 se você estiver lidando com nomes de arquivos estranhos), mas não requer a criação de um arquivo separado.

Daniel Beck
fonte
Não faz find Lidar com nomes de arquivos estranhos por conta própria? IIRC nunca há uma boa razão para usar find … -print0 | xargs -0 …
slhck
@slhck Newlines são componentes de nome de arquivo válidos. O seguinte demonstra como isso faz com que os scripts falhem: touch "$( echo -e 'foo\nbar' )" ; find . -name 'foo*bar' | xargs -n 1 echo File:
Daniel Beck
1

Você parece estar perdendo um {} no comando pandoc

find . -name \*.htm | xargs -I {} -n 1 pandoc -f html -t markdown {} -o {}.md

Mas então você terá arquivos nomeados 001.htm.md - você terá que decidir se isso é um problema.

glenn jackman
fonte