Перейменуйте кілька файлів за допомогою mv, щоб змінити розширення


27

Я хочу перейменувати файли, щоб змінити їх розширення, ефективно прагнучи виконати

mv *.txt *.tsv

Але при цьому я отримую:

* .tsv не є каталогом

Я вважаю дещо дивним, що перші 10 хітів шоу в Google mvповинні працювати так.


Ви повинні пояснити, як саме ви хочете перейменувати ці файли.
Тотор

1
Ну, у мене є файли з розширенням * .gappedPeak і хочу перейменувати їх на * .bed. всі вони в одному каталозі, це повинно бути дуже просто, але для успіху мені знадобилося повне цикл
Sander Van der Zeeuw

Те, що ви знайшли в 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. Якщо у вас є більше посилань, ви можете поділитися. Як і для чоловічих сторінок, на яких ви заявляєте, це виражено.


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 ), яка є поточним ім'ям файлу, до нового імені. Тут я збігаю підрядок і видаляю; тому знову візьміть перший var, $ 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

Чи можете ви пройти команду, що описує, що робить кожна частина?
користувач1717828

Пробачте, я оновив свій пост. Сподіваюся, що це допомагає.
devnull

1
Дивовижне, дякую! Завдяки керівництву по басу та вашим поясненням я зміг отримати все.
користувач1717828

Без проблем. Радий, що це допомагає.
devnull

Працює як шарм. Ось ще один спрощений приклад для file.abc-> blub.xyzу кількох підручниках:find . -name "file.abc" -exec sh -c 'mv "$1" "$(dirname $1)/blub.xyz"' _ {} \;
Ман

9

mv *.txt *.tsvне працює; mvможе перейменувати лише один файл одночасно. Ви або неправильно зрозуміли пояснення, або вони помиляються.

mmvі renameможе перейменувати кілька файлів одночасно. Але є дві версії, renameнавколо яких називаються по-різному. Тут має бути багато питань.


1
cyberciti.biz/tips/… Перший хіт на Google говорить про те, що телевізор повинен працювати так само, тому я вважаю це таким дивним
Sander Van der Zeeuw

3
@SanderVanderZeeuw Я не знаю, що ти там читаєш. Приклади використовують rename, не mv.
Hauke ​​Laging

1
вибачте, що я вставив неправильний HTML-код. Це був один udemy.com/blog/rename-a-file-in-linux
Sander Van der Zeeuw

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. Оскільки такого каталогу немає, він дає помилку.


Дякую, це частково з’ясовується. І все-таки мені здається дивним, що я бачу стільки сторінок керівництва, де вони стверджують, що телевізор повинен працювати на кількох.
Sander Van der Zeeuw

2

rename(1)

renameце сценарій Perl Ларрі Уолл, виробник Perl. Він займає регулярний вираз Perl і діє на ім'я файлу.

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

Установка

Debian / Ubuntu

Якщо вам потрібно встановити renameDebian / Ubuntu, ви можете це зробити

sudo apt install rename

0

Ще один варіант, який слід врахувати, - це використання:

cp -p *.txt *.tsv
rm -f *.txt
  • Перший рядок копіює всі *.txtфайли *.tsv, зберігаючи їх атрибути, використовуючи -pпрапор.
  • Другий рядок видаляє всі файли з малюнком *.txt
  • Цей метод вимагає, щоб у вас було достатньо місця на диску, щоб тимчасово вмістити як вихідні, так і цільові файли
  • Цей спосіб більш повільний, ніж mvякий просто змінює / каталог / ім'я файлу, фактично не переміщуючи файли, якщо вони не перебувають на іншому розділі.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.