Назад | Перейти на главную страницу

Измените шаблон первого символа в имени файла, не изменяя тот же шаблон в другом месте имени файла

На сервере Linux у меня есть каталог, полный файлов с цифрами в именах. Некоторые файлы начинаются с двух нулей, например 00305005. Я пишу сценарий оболочки bash, и одним из шагов является переименование всех файлов, начинающихся с 00, так, чтобы они начинались с @ 0. Файл, о котором я упоминал ранее, будет @ 0305005.

Проблема, с которой я столкнулся, заключается в том, что когда я пытаюсь переименовать файлы, я в конечном итоге меняю все экземпляры 00 в имени файла на @ 0 следующим образом: @ 0305 @ 05. Я использовал следующий код и не знаю, как его исправить:

for f in 00*; do mv "$f" "${f//00/@0}"; done

Если вы застряли с магией оболочки, перейдите по другому пути и попробуйте изменить имя файла с помощью другого инструмента, например f.ex. sed

for f in 00*; do
  new_f=$( echo "$f" | sed 's/00/@0/' )
  echo mv "$f" "$f_new"
done

Я вставил echo перед mv так что вы можете сначала проверить, если mvПосмотрите хорошо, прежде чем испортить свои файлы. Затем вы можете удалить это echo.

Когда вы используете ${var//pattern/replacement}, то \\ означает "заменить все случаев. В этом случае вы хотите заменить только первое вхождение, поэтому вы можете использовать только /. Или вы могли бы быть еще более конкретным и использовать /#, который заменит только начало строки; это не должно иметь значения, поскольку вы обрабатываете только файлы, начинающиеся с 00, но я был бы склонен использовать его, чтобы четко обозначить цель. Вот демо:

$ f=00305005
$ echo "${f//00/@0}"    # // = replace all
@0305@05
$ echo "${f/00/@0}"     # /  = replace first one -- this does what you want
@0305005
$ echo "${f/#00/@0}"    # /# = replace at beginning -- this also does what you want
@0305005
$ g=90305005            # Let's test with a name that *doesn't* start with 00
$ echo "${g/00/@0}"     # / replaces the first match, no matter where it is in the string
90305@05
$ echo "${g/#00/@0}"    # /# does not replace if the beginning does not match
90305005

Я также рекомендую использовать mv -i для любого вида массового перемещения / переименования, чтобы избежать потери данных в случае конфликта имен или ошибок. Итак, вот что я бы порекомендовал:

for f in 00*; do mv -i "$f" "${f/#00/@0}"; done