Переименовать/переместить (mv) несколько файлов, начиная с имени

Я пытаюсь переименовать несколько файлов, соответствующих шаблону, в одном каталоге.

Файлы:

stack_overflow_one.xml
stack_overflow_two.xml
stack_overflow_one.html

Я хотел бы переименовать stack_overflow в heap_graph

heap_graph_one.xml
heap_graph_two.xml
heap_graph_one.html

Я пробовал следующее:

Использование rename:

rename stack_overflow heap_graph stack_overflow* # returns 'The syntax of the command is incorrect.'

Использование цикла for в Bash

# how can I write this in one line? I've tried wrapping in one line, but also does not work
for i in stack_overflow* do
    mv "$i" "${i/stack_overflow/heap_graph}"
done

Однако ни один из них не работает.


person Kyle    schedule 19.09.2017    source источник
comment
Существует несколько различных реализаций rename, поддерживающих разные синтаксис — на моем ПК используется синтаксис rename s/stack_overflow/heap_graph/ stack_overflow*.   -  person gboffi    schedule 19.09.2017
comment
Используйте точки с запятой в цикле for, чтобы записать его в одну строку: for foo in bar; do something; done   -  person Olli K    schedule 19.09.2017
comment
Если вы нашли какой-либо из данных ответов полезным, см. Что мне делать, когда кто-то ответит на мой вопрос? и Что означает принятие ответа?   -  person Inian    schedule 27.09.2017


Ответы (2)


У вас есть тривиальная синтаксическая ошибка в цикле for. Остальная часть вашего скрипта должна работать без проблем.

for i in stack_overflow*; do
#                      ^^^ missing semi-colon
# The below condition to handle graceful loop termination when no files are found
    [ -f "$i" ] || continue
    mv "$i" "${i/stack_overflow/heap_graph}"
done

Как отмечено ghoti ниже, если вы находитесь в оболочке Bourne Again bash, а не в оболочке Bourne POSIX (sh), для которой приведенное выше решение является переносимым, вы можете использовать специальные параметры подстановки, чтобы избежать ситуации, когда вам не приходится иметь дело со случаем, когда glob не возвращает файлы.

shopt -s nullglob
for i in stack_overflow*; do
    mv "$i" "${i/stack_overflow/heap_graph}"
done

shopt -u nullglob

Опция -s устанавливает его, а -u отменяет. Дополнительные сведения о встроенном shopt см. на странице GNU bash< /а>

person Inian    schedule 19.09.2017

Полураспространенная утилита mmv (статья) полезна для случая "многоходов", который вы я описал.

$ mmv -n 'stack_overflow_*' 'heap_graph__#' # remove -n after testing
mv -- stack_overflow_one.html heap_graph_one.html
mv -- stack_overflow_one.xml heap_graph_one.xml
mv -- stack_overflow_two.xml heap_graph_two.xml

Как видите, он просто вызывает mv несколько раз для сопоставленных шаблонов.

* - это подстановочный знак, который использует Bash, но он экранирован кавычками для передачи в mmv. _# — это ссылка на совпадение, также экранированное (хотя в документах предполагается, что вместо этого будет работать #1).

Это семейство команд также удобно для копирования (cp) и связывания (ln).


Если у вас есть Zsh (обычное обновление/замена Bash), у вас уже есть zmv, который аналогичным образом будет выполнять эту работу:

% zmv -n 'stack_overflow_(*)' 'heap_graph_$1'
person Micah Elliott    schedule 19.09.2017