¿Por qué no funciona este comando xargs?

14

Quería eliminar todas las extensiones .sh, así que hice esto:

ls *.sh | xargs -I {} mv {} `basename {} .sh`

Sin embargo, no funciona, se comporta como basenamedevuelve el nombre del archivo sin cambios.

¿Por qué se comporta así?

Por ejemplo, esto funciona:

ls *.sh | xargs -I {} echo `basename {}.jpg .jpg`;

EDITAR :

Solución: la comilla simple impide la `basename ...`evaluación por parte del shell antes de ejecutar el comando.

ls *.sh | xargs -I {}  sh -c 'mv {} `basename {} .sh`'
majkinetor
fuente

Respuestas:

12

Porque el comando basename se ejecuta antes de que se ejecute la canalización. Para que esto funcione, necesita xargs para ejecutar basename y puede hacerlo con sh -c, por ejemplo:

ls *.sh | xargs -L1 sh -c 'basename $1 .sh' dummy

Notas:

  • Si no le dice xargsdónde insertar los nombres de archivo, se agregarán al final de la línea de comando.
  • Debe usar el -L1interruptor o su equivalente, por lo que xargssolo pasa un argumento ash .
  • El uso de la salida de lspuede tener efectos no deseados .

Editar

Se eliminaron las opciones obsoletas, gracias TechZilla

Thor
fuente
3
Su primer punto es incorrecto, a menos que haya querido decir que es el valor predeterminado correspondiente a la -iopción, pero esas opciones 'clásicas' han quedado en desuso. Por ejemplo, para usar solo una opción / línea, se recomienda la nueva página de manual POSIX -L1. Para llamar al comportamiento anterior de -i, la página recomienda la -I'{}'opción.
JM Becker
Entonces, en realidad se trata de símbolos '' en lugar de "". Supongo que 'evita la evaluación de shell de' '. Mira mis ediciones.
majkinetor
@TechZilla: gracias por las correcciones. @majkinetor: sí y no, debe retrasar la evaluación, pero no creo que pueda usar los backticks (`).
Thor
1
@majkinetor: ah, entiendo lo que quieres decir ahora. Para cambiar el nombre de archivos de esta manera me gustaría utilizar en lugar rename, por ejemplo: rename 's/\.sh//' *.sh. Pruebe primero con la ejecución en seco ( -n).
Thor
1
@majkinetor: renamefunciona muy bien y es bastante simple, pero recuerda que es muy específico de distribución. Las distribuciones basadas en RHEL y Debian proporcionan diferentes renamecomandos, por lo que hay que tener esto en cuenta al crear scripts de distribución cruzada.
JM Becker
4

No estoy seguro acerca de su pregunta, ¿realmente está preguntando por qué su primera línea no funciona? ¿O está buscando un método adecuado para cambiar el nombre de todos los archivos .sh?

Suponiendo que es el método más limpio, prefiero preparar las opciones de comando antes xargs. Para eliminar una extensión de archivo .sh, a menudo considero este enfoque,

 find -maxdepth 1 -type f -iname '*.sh'  | sed 'p;s_.sh$__' | xargs -L2 mv
JM Becker
fuente