Переименуйте несколько файлов с помощью mv, чтобы изменить расширение

27

Я хочу переименовать файлы, чтобы изменить их расширение, эффективно пытаясь достичь

mv *.txt *.tsv

Но при этом я получаю:

* .tsv не является каталогом

Я нахожу несколько странным, что первые 10 показов Google mvдолжны работать следующим образом.

Сандер ван дер Зеув
источник
Вы должны объяснить, как именно вы хотите переименовать эти файлы.
Тотор
1
Ну, у меня есть файлы с расширением * .gappedPeak и я хочу переименовать их в * .bed. все они находятся в одном каталоге, это должно быть очень просто, но мне нужен был полный цикл for
Сандер Ван дер Зеув
То, что вы нашли в Google, относится к MSDOS, я думаю.
Тиктак
Альтернативное решение
@devnull

Ответы:

22

Когда вы вводите команду:

mv *.txt *.tsv

оболочка, предположим bash, расширяет символы подстановки, если есть какие-либо подходящие файлы (включая каталоги). Список файлов передается в программу, здесь mv. Если совпадений не найдено, расширенная версия пропускается.

Опять же: оболочка расширяет шаблоны, а не программу.


Множество примеров, пожалуй, лучший способ, так что здесь мы идем:

Пример 1:

$ ls
file1.txt file2.txt

$ mv *.txt *.tsv

Теперь в mvстроке происходит то, что оболочка расширяется *.txtдо соответствующих файлов. Как нет *.tsvфайлов, которые не изменены.

Команда mvвызывается с двумя специальными аргументами :

  • argc: Количество аргументов, включая программу.
  • argv: Массив аргументов, включая программу в качестве первой записи.

В приведенном выше примере это будет:

 argc = 4
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = file2.txt
 argv[3] = *.tsv

mvПроверка программы , чтобы увидеть , если последний аргумент, *.tsvявляется каталогом. Поскольку это не так, программа не может продолжаться, так как она не предназначена для объединения файлов. (Обычно перемещают все файлы в один.) И не создавайте каталоги по прихоти.

В результате он прерывает работу и сообщает об ошибке:

mv: target ‘*.tsv’ is not a directory

Пример 2:

Теперь, если вы вместо этого скажете:

$ mv *1.txt *.tsv

Команда mvвыполняется с:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = *.tsv

Теперь, снова, mvпроверьте, если *.tsvсуществует. Поскольку это не файл file1.txtперемещен в *.tsv. То есть: файл переименован *.tsvв звездочку и все.

$ mv *1.txt *.tsv
‘file1.txt’ -> ‘*.tsv’

$ ls
file2.txt *.tsv

Пример 3:

Если вы вместо этого сказали:

$ mkdir *.tsv
$ mv *.txt *.tsv

Команда mvвыполняется с:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[1] = file2.txt
 argv[2] = *.tsv

Поскольку *.tsvтеперь это каталог, файлы в конечном итоге перемещаются туда.


Теперь: используя команды, например, some_command *.tsvкогда намерение состоит в том, чтобы на самом деле оставить подстановочный знак, его всегда следует заключать в кавычки. Заключая в кавычки, вы препятствуете расширению подстановочных знаков, если должны быть какие-либо совпадения. Например, сказать mkdir "*.tsv".

Пример 4:

Расширение можно просмотреть, если вы сделаете, например:

$ ls
file1.txt file2.txt

$ mkdir *.txt
mkdir: cannot create directory ‘file1.txt’: File exists
mkdir: cannot create directory ‘file2.txt’: File exists

Пример 5:

Теперь: mvкоманда может работать над несколькими файлами. Но если их больше двух, последний должен быть целевым каталогом. (При желании вы можете использовать -t TARGET_DIRопцию, по крайней мере, для GNU mv.)

Так что все в порядке:

$ ls -F
b1.tsv  b2.tsv  f1.txt  f2.txt  f3.txt  foo/

$ mv *.txt *.tsv foo

Здесь mvбудет называться с:

 argc = 7
 argv[0] = mv
 argv[1] = b1.tsv
 argv[2] = b2.tsv
 argv[3] = f1.txt
 argv[4] = f2.txt
 argv[5] = f3.txt
 argv[6] = foo

и все файлы попадают в каталог foo.


Что касается ваших ссылок. Вы предоставили один (в комментарии), где mvвообще не упоминается, но rename. Если у вас есть больше ссылок, вы могли бы поделиться. Как и для страниц руководства, где вы заявляете, это выражено.

Runium
источник
30

Я знаю, что это не отвечает на ваш вопрос, но если вы искали другой способ переименования файлов по сравнению с циклом обхода, почему бы не использовать find? Я много раз использовал эту команду, чтобы заменить расширения файлов в больших каталогах сотнями тысяч файлов. Это должно работать на любой POSIX-совместимой системе:

find . -name "*.gappedPeak" -exec sh -c 'mv "$1" "${1%.gappedPeak}.bed"' _ {} \;

Распределение команд:

  1. ' .' => Путь поиска, начиная с текущего каталога, отмеченного как '. '

  2. -name=> установить поиск соответствия имени (в этом случае все файлы, которые заканчиваются .gappedPeak)

  3. -exec => выполнять следующую команду при каждом совпадении

  4. sh -c => 'exec' создает независимую среду оболочки для каждого совпадения

  5. mv "$1" "${1%.gappedPeak}.bed"=> mvпервая переменная (обозначается $ 1 ), которая является текущим именем файла, с новым именем. Здесь я делаю совпадение подстроки и удаляю; поэтому возьмите первый переменный снова, $ 1 и используйте %для удаления .gappedPeakиз строки. .bedВ конце концов просто присоединяет оставшуюся переменную, которая теперь просто , с , создавая новое имя файла.test#.bedtest#.bed

  6. Подчеркивание является заполнителем для $ 0

  7. Символ {}заменяется каждым ( *.gappedPeak) именем файла, найденным findкомандой, и становится $ 1 для shкоманды.

  8. \;отмечает конец -execкоманды. Вы также можете использовать ';'или ";".

Пример:

[user@before]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.gappedPeak

[user@after]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.bed
devnull
источник
Не могли бы вы пройти команду, описывающую, что делает каждая часть?
user1717828
Я сожалею об этом, я обновил свой пост. Надеюсь, это поможет.
devnull
1
Круто, спасибо! С руководством bash и вашим объяснением я смог получить все.
user1717828
Нет проблем. Рад, что это помогает.
devnull
Работает как шарм. Вот еще один упрощенный пример для file.abc-> blub.xyzв нескольких подкаталогах:find . -name "file.abc" -exec sh -c 'mv "$1" "$(dirname $1)/blub.xyz"' _ {} \;
Mahn
9

mv *.txt *.tsvне работает; mvможет переименовывать только один файл за раз. Вы либо неправильно поняли объяснения, либо они неверны.

mmvи renameможет переименовать несколько файлов одновременно. Но есть две версии renameвокруг, которые называются по-разному. Здесь должно быть много вопросов об этом.

Хауке Лагинг
источник
1
cyberciti.biz/tips/… Первый хит на Google говорит, что mv должен работать так же хорошо, поэтому я нахожу это таким странным
Сандер Ван дер Зеув
3
@SanderVanderZeeuw Я не знаю, что вы там читаете. Примеры использования rename, а не mv.
Хауке Лагинг
1
извините, я вставил неправильный HTML. Это был один udemy.com/blog/rename-a-file-in-linux
Сандер Ван дер Зеув
3
@SanderVanderZeeuw Смущает. Эти люди предлагают курсы? К сожалению, я не вижу возможности контакта там. Вы можете легко проверить, работает ли это. Но в mv *.txt *.tsv mv(обычно) не видит *.txtили *.tsvтолько имена файлов, расширенных оболочкой. Количество файлов, к которым расширяются эти символы, будет «случайным». Единственная ситуация, когда это работает, - это наличие файла с именем, *.txtкоторое должно быть переименовано (буквально) *.tsv(без цитирования bashопция nullglobне должна быть установлена).
Hauke ​​Laging
1
Или хуже. Если один есть один файл с именем , например , foo.txtи один с именем перезаписывает существующий файл ...baz.tsvmv *.txt *.tsv.tsv
Runium
4

Например, если у вас есть asd.txtи qwe.txtфайлы в каталоге при выполнении команды mv *.txt *.tsv, он пытается переместить эти файлы в папку с именем *.tsv. Поскольку такого каталога нет, выдается ошибка.

Esref
источник
Спасибо, это проясняет частично. Тем не менее я нахожу странным, что я вижу так много справочных страниц, где утверждают, что mv должен работать на нескольких.
Сандер Ван дер Зеув
2

rename(1)

renameсценарий Perl Ларри Уолла, создателя Perl. Он принимает регулярное выражение Perl и работает с именем файла.

rename 's/\.txt$/.tsv/' *.txt

Установка

Debian / Ubuntu

Если вам нужно установить renameна Debian / Ubuntu, вы можете сделать

sudo apt install rename
Эван Кэрролл
источник
0

Еще один вариант, который стоит рассмотреть:

cp -p *.txt *.tsv
rm -f *.txt
  • Первая строка копирует все *.txtфайлы *.tsv, сохраняя их атрибуты с использованием -pфлага.
  • Вторая строка удаляет все файлы с рисунком *.txt
  • Этот метод требует, чтобы у вас было достаточно места на диске для временного хранения как исходного, так и целевого файлов.
  • Этот метод медленнее, чем mvпросто изменение каталога / directory / filename без фактического перемещения файлов, если они не находятся в другом разделе.
WinEunuuchs2Unix
источник