Por que esse comando xargs não funciona?

14

Eu queria excluir todas as extensões .sh, o que fiz:

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

No entanto, ele não funciona, ele se comporta como basenameretorna o nome do arquivo inalterado.

Por que está se comportando dessa maneira?

Por exemplo, isso funciona:

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

EDIT :

Solução: aspas simples impedem a `basename ...`avaliação pelo shell antes da execução do comando.

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

Respostas:

12

Porque o comando basename é executado antes da execução do pipeline. Para fazer isso funcionar, você precisa do xargs para executar o nome da base e pode fazer isso com sh -c, por exemplo:

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

Notas:

  • Se você não informar xargsonde inserir os nomes dos arquivos, eles serão adicionados no final da linha de comando.
  • Você deve usar a -L1opção ou equivalente, para que xargsapenas passe um argumento para sh.
  • O uso da saída de lspode ter efeitos indesejados .

Editar

Removidas opções obsoletas, obrigado TechZilla

Thor
fonte
3
Seu primeiro ponto está incorreto, a menos que você queira dizer que é o padrão respectivo da -iopção, mas essas opções 'clássicas' foram preteridas. Por exemplo, para usar apenas uma opção / linha, a nova página do manual POSIX recomenda -L1. Para chamar o comportamento antigo de -i, a página recomenda a -I'{}'opção.
JM Becker
Então, na verdade, trata-se de símbolos "". Eu acho que 'impede a avaliação do shell de ``. Veja minhas edições.
majkinetor
@ TechZilla: obrigado pelas correções. @ majkinetor: sim e não, você precisa adiar a avaliação, mas acho que não pode usar backticks (`).
Thor
1
@ majkinetor: ah, entendo o que você quer dizer agora. Para renomear arquivos dessa maneira eu prefiro usar rename, por exemplo: rename 's/\.sh//' *.sh. Tente primeiro com o dry-run ( -n).
Thor
1
@ majkinetor: renamefunciona muito bem e é bastante simples, mas lembre-se de que é muito específico para a distribuição. As distribuições baseadas em RHEL e Debian fornecem renamecomandos diferentes , portanto, é preciso ter isso em mente ao criar scripts de distribuição cruzada.
JM Becker
4

Não tenho certeza sobre sua pergunta, você está realmente perguntando por que sua primeira linha não funciona? Ou você está procurando um método adequado para renomear todos os arquivos .sh?

Supondo que seja o método mais limpo, prefiro preparar as opções de comando antes xargs. Para remover uma extensão de arquivo .sh, costumo considerar essa abordagem,

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