Linux mv файл с длинным именем

19

В Linux я иногда переименовываю файлы следующим образом:

mv dir1/dir2/dir3/file.txt  dir1/dir2/dir3/file.txt.old

Обратите внимание, что я хочу просто переименовать файл, а не переместить его в другой каталог.

Есть ли команда, которая позволила бы мне сделать сокращенную версию этой команды? Я думаю что-то вроде:

mv dir1/dir2/dir3/file.txt  file.txt.old

или даже что-то вроде (просто добавить к имени):

mv dir1/dir2/dir3/file.txt  {}.old

Моя цель не состоит в том, чтобы снова указывать полный путь.

Я знаю, что те «примеры», которые я написал, не работают, но это просто идея того, чего я хочу достичь.

Я не хочу заходить в каталог.

Сантьяго Аристи
источник
8
Почему бы вам не перейти в каталог? Это быстро и решает вашу проблему.
Майкл Хэмптон
Я имею дело со многими подкаталогами из этого же места, и медленнее, если мне приходится каждый раз возвращаться к этому родительскому
каталогу
3
Никто не говорил, что вам нужно перейти на другой каталог, только тот, который вы хотите.
Майкл Хэмптон
Обратите внимание, что он (cd dir1/dir2/dir3 && exec mv file.txt{,.old})имеет практически ту же производительность, что и код без подпроцесса, поскольку он execпозволяет избежать fork()вызова во время внешнего вызова команды, поэтому в любом случае вы получаете ровно один форк.
Чарльз Даффи

Ответы:

45

для одного файла попробуйте

mv dir1/dir2/dir3/file.{txt,txt.old}

где X{a,b}конструкция расширяется до Xa Xb, вы можете иметь предварительный просмотр, используя

echo dir1/dir2/dir3/file.{txt,txt.old}

чтобы увидеть, если это соответствует вашим потребностям.

нота:

  1. что за несколько файлов

    mv dir1/dir2/dir3/file{1,2,3}.{txt,txt.old}
    

вряд ли расширится до того, что вы хотите. (это расширится до смешанного файла file.txt file1.txt.old file2.txt ...)

  1. {txt,txt.old}может быть сокращено {,.old}в соответствии с комментарием

  2. если имя каталога однозначно, можно использовать подстановочный знак.

    mv *1/*2/d*/*.{,old}
    

для использования в нескольких файлах rename

rename -n s/txt/old.txt/ dir1/dir2/dir3/file*.txt 

падение, -nчтобы иметь эффективное переименование.

Archemar
источник
1
хорошо, я не знал этот способ расширения! спасибо
Сантьяго Аристи
14
Не mv dir1/dir2/dir3/file.txt{,.old}будет также работать, и будет еще короче?
Джош
3
@ Джош Да, это работает отлично и требует меньше нажатий клавиш. Я использую эту конструкцию очень регулярно.
рф
2
Забавно, что вы можете годами использовать оболочку Linux и постоянно находить новые приемы
santiago arizti
Я думаю, что все эти «уловки» были бы более очевидными, если бы у меня была некоторая формальная подготовка по языку bash, но я только учился достаточно, чтобы ладить.
Сантьяго Аристи
6

Команда renameпереименовывает все совпадающие файлы. Его основная цель - переименовать несколько файлов, но если выражение Perl соответствует только одному файлу, оно переименует только этот единственный файл. Для получения дополнительной информации и дистро синтаксиса конкретного пожалуйста прочитайте страницу руководства: man rename.

Пример использования: переименуйте "/path/file.txt" в "/path/file.txt.old":

rename 's/file.txt/file.txt.old/g' /path/file.txt

Более короткое обозначение (благодаря шаломбу):

rename 's/$/.old/' /path/file.txt
rename '$_.=".old"' /path/file.txt

Для пробного использования rename -n.

Дополнительные примеры и подробности можно найти по адресу https://thepcspy.com/read/bulk-rename-files-in-ubuntu/.

Fabian
источник
круто, я знал про команду переименования, просто никогда не знал всего, что она могла сделать, спасибо!
Сантьяго Аристи
6
К сожалению, разные дистрибутивы Linux имеют разные renameкоманды с совершенно разным поведением.
Касперд
1
Для этой конкретной задачи переименования путем добавления .oldк имени файла, возможно, немного удобнее сделать rename 's/$/.old/' /path/to/file.txtилиrename '$_.=".old"' /path/to/file.txt
shalomb
@Fabian - Я не придираюсь, просто стремлюсь к «самой короткой руке» для того, что, кажется, часто используется идиома, которую ищет ОП :)
shalomb
4

Для одноразового случая, если я не хочу менять свой текущий каталог, я мог бы просто использовать вспомогательную оболочку:

(cd dir1/dir2/dir3/ && mv file.txt file.txt.old)

Поскольку вы cdвнутри под-оболочки, вы не изменили свой каталог в вашей реальной оболочке

Адам
источник
4
Быстрее и безопаснее в использовании && exec mv- таким образом, вы не пытаетесь переименовать, если происходит cdсбой, и execпотребляет подоболочку, что позволяет избежать потери производительности.
Чарльз Даффи
Согласитесь с « && Единовременным делом», как я уже сказал, я не буду беспокоиться о стоимости вспомогательной оболочки (будьте проще: возможность легко запомнить, как это сделать, важнее для ИМО)
Адам
Я бы сказал, что если вы запомните только один путь, запомните эффективный путь, который поможет вам не идти неэффективным путем в тех случаях, когда это имеет значение.
Чарльз Даффи
4

Мне нравится решение @ archemar использовать расширение {}, потому что вы можете использовать его, когда уже запустили командную строку. Вот некоторые другие возможности для полноты:

F="dir1/dir2/dir3/file.txt" ; mv "$F" "$F.old"

(кавычки необходимы только в том случае, если в названии есть пробелы или другие символы перевода слов)

mymv() {
    mv "$1/$2" "$1/$3"
}

mymv dir1/dir2/dir3 file.txt file.txt.old
mymv dir5/dir6/dir7 file.txt file.txt.old

Примечания:

  • Это синтаксис bash, возможно, вы используете другую оболочку
  • mymv может быть любая разумная строка, я использовал mymv для "моего хода".
  • Определение функции может быть помещено в ваш .bash_profile

Еще один:

cd dir1/dir2/dir3 ; mv file.txt file.txt.old ; cd -

но

(cd dir1/dir2/dir3/ && exec mv file.txt file.txt.old)

(от @Adam и @CharlesDuffy) возможно лучше в случае сбоя компакт-диска.

Law29
источник
1
Не используйте mmv, уже существует программа с таким названием.
glglgl
1
@glglgl Готово :)
Закон 29
2

Если вы хотите войти в подкаталог, чтобы сократить mvкоманду, но потом хотите вернуться в текущий каталог, есть два способа сделать это. Одним из них является положить cdи mvв подоболочку (как уже было предложено).

Другой - использовать pushdи popdизменять каталоги:

pushd dir1/dir2/dir3/; mv file.txt file.txt.old; popd

Команда pushdпохожа cd, за исключением того, что она сначала помещает имя текущего каталога в стек. popdудаляет верхнее имя из стека и изменяет этот каталог.

AndyB
источник
pushdи popdявляются расширениями, предназначенными для интерактивного использования - POSIX явно перечисляет их как «результаты не определены», и оболочка, созданная для запуска сценариев (т. е. в минимальной встроенной среде), не должна их поддерживать.
Чарльз Даффи
2

Я бы просто сделал

cd dir1/dir2/dir3/
mv file.txt file.txt.old
cd ~- # go to the most recent directory
glglgl
источник
0

Решение включает в себя: mv something{.txt,.txt.old}использование "bashism". Если вы хотите более портативный способ, используя обычные манипуляции с переменными:

# rename all files "file*.txt" of directory /dir1/dir2/dir3 into file*.txt.old:
for f in dir1/dir2/dir3/file*.txt ; do
  mv "$f" "${f/.txt/.txt.old}"  # note there are no terminating "/"
done


# "${var/A/B}" is the content of var with the first occurence of "A" replaced by "B"
Оливье Дюлак
источник
2
См. Pubs.opengroup.org/onlinepubs/009695399/utilities/… для соответствующей спецификации POSIX - ${var/text/replacement}это сам по себе башизм.
Чарльз Даффи
@CharlesDuffy о ... Вы меня огорчаете :(
Оливье Дюлак