Почему эта команда xargs не работает?

14

Я хотел удалить все расширения .sh, поэтому сделал это:

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

Однако это не работает, оно ведет себя как basenameвозвращает неизменное имя файла.

Почему так себя ведет?

Например, это работает:

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

РЕДАКТИРОВАТЬ :

Решение: одинарная кавычка предотвращает `basename ...`оценку оболочкой до запуска команды.

ls *.sh | xargs -I {}  sh -c 'mv {} `basename {} .sh`'
majkinetor
источник

Ответы:

12

Потому что команда basename запускается до запуска конвейера. Чтобы сделать это, вам нужен xargs для выполнения basename, и вы можете сделать это sh -c, например:

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

Примечания:

  • Если вы не укажете, xargsкуда вставлять имена файлов, они будут добавлены в конце командной строки.
  • Вы должны использовать -L1переключатель или его эквивалент, поэтому xargsпередается только один аргумент sh.
  • Использование вывода lsможет иметь нежелательные эффекты .

редактировать

Удалены устаревшие опции, спасибо TechZilla

Тор
источник
3
Ваш первый пункт неверен, если только вы не имели в виду, что по умолчанию он соответствует -iопции, но эти «классические» опции устарели. Например, чтобы использовать только одну опцию / строку, рекомендуется новая справочная страница POSIX -L1. Чтобы вызвать старое поведение -i, страница рекомендует эту -I'{}'опцию.
Дж. М. Беккер
Таким образом, на самом деле речь идет о символах «вместо». Я предполагаю, что 'предотвращает оценку оболочки ``. Смотрите мои правки.
majkinetor
@TechZilla: спасибо за исправления. @majkinetor: да и нет, вам нужно отложить оценку, но я не думаю, что вы можете использовать обратные пометки (`).
Четверг,
1
@majkinetor: ах, теперь я понимаю, что вы имеете в виду. Для того, чтобы переименовать файлы таким образом , я предпочел бы использовать rename, например: rename 's/\.sh//' *.sh. Попробуйте сначала с сухим прогоном ( -n).
Тор
1
@majkinetor: renameработает отлично и довольно просто, но помните, что это очень специфично для дистрибутива. Дистрибутивы, основанные на RHEL и Debian, предоставляют разные renameкоманды, поэтому об этом следует помнить при создании кросс-дистрибутивных скриптов.
Дж. М. Беккер
4

Я не уверен в вашем вопросе, вы на самом деле спрашиваете, почему ваша первая строка не работает? Или вы ищете правильный способ переименовать все файлы .sh?

Предполагая, что это самый чистый метод, я предпочитаю подготовить параметры команд раньше xargs. Для удаления расширения .sh я часто рассматриваю этот подход,

 find -maxdepth 1 -type f -iname '*.sh'  | sed 'p;s_.sh$__' | xargs -L2 mv
Дж. М. Беккер
источник