it-swarm.com.ru

Пакетное переименование файлов в командной строке и Xargs

Итак, у меня есть следующая структура:

.
..
a.png
b.png 
c.png

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

ls | xargs -I xx convert xx -resize xx.jpg

Теперь мой режиссер выглядит так

.
..
a.png.jpg
a.png
b.png.jpg
b.png
c.png.jpg
c.png

Первый вопрос: как мне переименовать файл, чтобы у меня было только одно расширение? Не два. (в основном, как мне исправить мою первоначальную ошибку)?

Второй вопрос - в будущем, используя xargs, как мне изменить расширение файла simular на вторую команду?

22
Cripto

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

cd dir/with/messedup/files

for file in *.png.jpg; do
  mv "$file" "${file%.png.jpg}.jpg"
done

в будущем, используя xargs, как изменить расширение файла simular на вторую команду?

Насколько мне известно, это не может быть сделано. Лучший способ сделать это - использовать цикл for с подстановкой параметров, как показано выше:

for file in *.png; do
  convert "$file" -resize "${file%.png}.jpg"
done

Если у вас есть файлы в подкаталогах, которые вы хотите преобразовать, вы можете передать find в цикл while read:

find . -type f -name '*.png' |
while read file; do
  convert "$file" -resize "${file%.png}.jpg"
done

ПРИМЕЧАНИЕ: Обычно считается плохой идеей использовать вывод ls в сценарии оболочки. Хотя ваш пример мог бы работать нормально, есть много примеров, где это не так. Например, если в ваших именах файлов есть символы новой строки (что позволяет unix), ls, вероятно, не сможет их избежать. (Это на самом деле зависит от вашей реализации, что является еще одной причиной не использовать ls в сценариях; его поведение сильно варьируется от одного поля к другому.) Вы получите более согласованные результаты, если будете использовать find в цикле while-read или Глобализация файла (например, *.png) в цикле for.

19
Tim Pote

Это также можно сделать с помощью xargs и sed, чтобы изменить расширение файла.

ls | grep \.png$ | sed 'p;s/\.png/\.jpg/' | xargs -n2 mv

Вы можете распечатать оригинальное имя файла вместе с тем, что вы хотите, чтобы имя файла было. Затем пусть Xargs использует эти два аргумента в команде перемещения. Для однострочника я также добавил grep для фильтрации чего-либо, кроме файла * .png.

49
Schleis

Опаздываете на вечеринку, но вот как вы можете переименовать файлы с помощью xargs. Скажем, у вас есть набор файлов с именем fileN.svg.png, и вы хотите назвать их fileN.png, где N может быть серией целых чисел:

ls *.svg.png | xargs basename -s .svg.png | xargs -I {} mv {}.svg.png {}.png

Первый xargs использует basename для удаления обоих .svg и .png, чтобы получить просто filenameN. Второй xargs получает это голое имя и использует замену для переименования файла.

10
Dethe

Чтобы устранить ошибку, попробуйте утилиту rename. Проверьте man-страницу для деталей.

В вашем случае вы бы сделали rename '.png.jpg' '.jpg' ./*, если ваш текущий каталог настроен соответствующим образом.

Поскольку у вас есть convert, я предполагаю, что у вас также есть mogrify (imagemagick suite). Всякий раз, когда я хочу сделать это, я копирую файлы в другой каталог и использую вместо него mogrify. Обычно мне это нужно только для изменения размера, но если вы также измените формат изображения, mogrify будет обрабатывать имена файлов (создавать новые файлы с правильными именами файлов).

Вы бы использовали его как mogrify -format jpg -resize [size] ./*.png. Я не уверен, что -resize без аргументов геометрии должен делать. Это не задокументировано и не работает на моей машине.

Как рассуждал Тим Пот, я не думаю, что вы можете заставить xargs обрабатывать имена файлов и расширения отдельно.

6
Matej

Я опоздал на эту вечеринку примерно на 3 года, у меня просто была похожая проблема, которую я сам решил. У меня был список файлов png, которые я конвертировал с помощью inkscape, потому что поддержка ImageMagick svg плохая. 

Я первоначально преобразовал их, выполнив:

find . -name "*.svg" -exec inkscape {} --export-png={}.png

Что, конечно, привело к той же самой проблеме, как отправлено выше.

file1.svg
file1.svg.png
file2.svg
file2.svg.png
file3.svg
file3.svg.png
file4.svg
file4.svg.png

Я хотел переименовать * .svg.png в * .png, вот с чем я и столкнулся ...

find . -name "*.svg.png" -print0 | sed 's/.svg.png//g' | xargs -0 -I namePrefix mv namePrefix.svg.png namePrefix.png

Это делает три вещи:

  1. найти в этом каталоге файлы с именем * .svg.png, -print0 выводит на стандартный вывод
  2. sed изменяет стандартный вывод, в основном меняя местами файл .svg.png, поэтому я получу: file1/file2/file3/file4
  3. xargs -0 для получения данных из sed, -I ссылается на имя файла без расширения, затем mv оригинальное имя файла на новое имя файла. В Word namePrefix нет ничего особенного, просто хотелось прояснить это.

ПРАВКА

Теперь я понимаю, что это самый запутанный способ сделать это. Можно просто использовать команду переименования.

rename 's/svg\.png/.png/' *
3
Paul J

Мое решение похоже на многие решения xarg и особенно похоже на Schleis.

Разница в этом заключается в полной манипуляции с регулярными выражениями ссылками на совпадения и командами sed, которые должным образом игнорируют файлы, которые не совпадают, поэтому вам не нужно предварительно фильтровать свои данные.

Это также безопасно для файлов с пробелами и мета-оболочки.

Измените \2 в замене на любое желаемое расширение.

ls |
sed -nE 's/Rick\.and\.Morty\.(S03E[0-9]{2})\..*(\.[a-z0-9]{3})/"&" "Rick and Morty \1\2"/;T;p' |
xargs -n 2 mv

Объяснение

Аргумент -n говорит, что по умолчанию ничего не печатается, команда T сообщает, что переход к концу сценария выполняется, если предыдущая команда s не выполняла замену, команда p печатает пространство шаблона (выполняется только при совпадении команды s ).

& в замене является ссылкой на содержимое исходного совпадения имени файла.

Если мы заменим mv в команде на bash -c 'echo "run($#) [email protected]"' bash, то увидим, сколько раз будет вызываться mv, а также количество параметров и значение:

$ ls |
  sed -nE 's/Rick\.and\.Morty\.(S03E[0-9]{2})\..*(\.[a-z0-9]{3})/"&" "Rick and Morty \1\2"/;T;p' |
  xargs -n 2 bash -c 'echo "run($#) [email protected]"' bash
run(2) Rick.and.Morty.S03E02.720p.HDTV.x264-BATV.mkv Rick and Morty S03E02.mkv
run(2) Rick.and.Morty.S03E03.720p.HDTV.x264-BATV.mkv Rick and Morty S03E03.mkv
run(2) Rick.and.Morty.S03E04.720p.HDTV.x264-BATV.mkv Rick and Morty S03E04.mkv
run(2) Rick.and.Morty.S03E05.HDTV.x264-BATV[ettv].mkv Rick and Morty S03E05.mkv
run(2) Rick.and.Morty.S03E06.720p.HDTV.x264-BATV.mkv Rick and Morty S03E06.mkv
run(2) Rick.and.Morty.S03E06.HDTV.x264-BATV.mkv Rick and Morty S03E06.mkv
run(2) Rick.and.Morty.S03E07.720p.HDTV.x264-BATV[ettv].mkv Rick and Morty S03E07.mkv
run(2) Rick.and.Morty.S03E08.720p.HDTV.x264-BATV.mkv Rick and Morty S03E08.mkv
run(2) Rick.and.Morty.S03E09.720p.HDTV.x264-BATV.mkv Rick and Morty S03E09.mkv
run(2) Rick.and.Morty.S03E10.720p.HDTV.x264-BATV.mkv Rick and Morty S03E10.mkv
1
joshperry

Моя попытка из: https://www.tecmint.com/linux-image-conversion-tools/

ls -1 *.png | xargs -n 1 bash -c 'convert "$0" "${0%.png}.jpg"'

Используя параллель

parallel convert '{}' '{.}.jpg' ::: *.png
0
SergioAraujo