Separe el nombre de archivo y la ruta dentro de la opción -exec del comando de búsqueda

Separe el nombre de archivo y la ruta dentro de la opción -exec del comando de búsqueda

Tengo dificultades para escapar y evaluar la expresión. Estoy intentando ejecutar un comando dentro de una find... -exec COMMANDestructura, donde COMMANDopera en un archivo y genera salida a la salida estándar. Para usar esto COMMANDnormalmente en la línea de comando, simplemente redirijo a un archivo nuevo, como este:

COMMAND inputfilename.md > outputfilename.md.conf

Esto funciona bien. Sin embargo, si quiero recorrer recursivamenteTODOlos archivos en un directorio y su subdirectorio, usando find -exec, parece que no puedo entender cómo separar el nombre del archivo y la ruta para poder redirigir correctamente. Por ejemplo, esto produce un error:

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

porque {}expande toda la ruta del archivo. Probé varias combinaciones de basenamey dirname, pero parece que no puedo lograr que se evalúen (en cambio, solo obtengo la cadena 'nombre base', etc.). Por ejemplo, esto no funcionó porque el texto 'nombre base' simplemente aparece

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

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

Cualquier ayuda sería apreciada. En resumen, el objetivo es:

  1. Iterar recursivamente sobre todos los archivos que coinciden *.mden un directorio
  2. Ejecute COMMAND inputfile.md > ~/newdirectory/inputfile.md.confdonde inputfileestá la misma cadena en cada iteración.

¡Gracias!

Respuesta1

Hagas lo que hagas, necesitarás invocar un shell para realizar la redirección de la salida del comando a un archivo cuya ubicación depende del findresultado.

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

No sustituya {}dentro del script de shell. Esto no es compatible con todos los sistemas, e incluso donde lo es, no funcionaría en general, ya que trataría el nombre del archivo como una parte de la sintaxis del shell, por ejemplo, un archivo llamado ;rm -rf ~;.mdharía que usted borrara todos sus archivos.

${0##*/}utiliza manipulación pura de cadenas para obtener el nombre base del archivo. También podrías usar $(basename -- "$0").

Respuesta2

Si findaceptas -execdir, esto debería 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' _ {} +

información relacionada