Переименовать несколько файлов в Unix
В каталоге несколько файлов, начинающихся с префикса fgh
, например:
fghfilea
fghfileb
fghfilec
Я хочу переименовать их все, чтобы начать с префикса jkl
, Есть ли одна команда, чтобы сделать это вместо переименования каждого файла в отдельности?
26 ответов
Есть несколько способов, но с помощью rename
вероятно будет самым легким.
Используя одну версию rename
:
rename 's/^fgh/jkl/' fgh*
Используя другую версию rename
(так же, как ответ Judy2K):
rename fgh jkl fgh*
Вы должны проверить страницу руководства вашей платформы, чтобы увидеть, что из вышеперечисленного применимо.
Вот как sed
а также mv
можно использовать вместе для переименования:
for f in fgh*; do mv "$f" $(echo "$f" | sed 's/^fgh/jkl/g'); done
Согласно комментарию ниже, если в именах файлов есть пробелы, кавычки, возможно, должны окружать подфункцию, которая возвращает имя для перемещения файлов:
for f in fgh*; do mv "$f" "$(echo $f | sed 's/^fgh/jkl/g')"; done
Переименование может быть не в каждой системе. так что если у вас его нет, используйте оболочку этого примера в bash shell
for f in fgh*; do mv "$f" "${f/fgh/xxx}";done
Есть много способов сделать это (не все из них будут работать на всех системах Unixy):
ls | cut -c4- | xargs -I§ mv fgh§ jkl§
§ можно заменить на что угодно. Вы могли бы сделать это с
find -exec
тоже, но это ведет себя немного по-разному во многих системах, поэтому я обычно избегаюfor f in fgh*; do mv "$f" "${f/fgh/jkl}";done
Грубый но эффективный как говорится
rename 's/^fgh/jkl/' fgh*
Очень мило, но переименования нет в BSD, которая является самой распространенной системой Unix на данный момент.
rename fgh jkl fgh*
ls | perl -ne 'chomp; next unless -e; $o = $_; s/fgh/jkl/; next if -e; rename $o, $_';
Если вы настаиваете на использовании Perl, но в вашей системе нет переименования, вы можете использовать этого монстра.
Некоторые из них немного запутаны, и этот список далеко не полон, но вы найдете то, что вам нужно здесь, практически для всех Unix-систем.
С помощью find
, xargs
а также sed
:
find . -name "fgh*" -type f -print0 | xargs -0 -I {} sh -c 'mv "{}" "$(dirname "{}")/`echo $(basename "{}") | sed 's/^fgh/jkl/g'`"'
Это сложнее, чем решение @nik, но позволяет рекурсивно переименовывать файлы. Например, структура,
.
├── fghdir
│ ├── fdhfilea
│ └── fghfilea
├── fghfile\ e
├── fghfilea
├── fghfileb
├── fghfilec
└── other
├── fghfile\ e
├── fghfilea
├── fghfileb
└── fghfilec
будет преобразован в это,
.
├── fghdir
│ ├── fdhfilea
│ └── jklfilea
├── jklfile\ e
├── jklfilea
├── jklfileb
├── jklfilec
└── other
├── jklfile\ e
├── jklfilea
├── jklfileb
└── jklfilec
Ключ, чтобы заставить это работать с xargs
это вызвать оболочку из xargs.
Общая команда будет
find /path/to/files -name '<search>*' -exec bash -c 'mv $0 ${0/<search>/<replace>}' {} \;
куда
<search>
а также
<replace>
должны быть заменены вашим источником и целью соответственно.
В качестве более конкретного примера, адаптированного к вашей проблеме (следует запускать из той же папки, где находятся ваши файлы), приведенная выше команда будет выглядеть так:
find . -name 'gfh*' -exec bash -c 'mv $0 ${0/gfh/jkl}' {} \;
Для "пробного прогона" добавить
echo
до
mv
, чтобы вы видели, какие команды генерируются:
find . -name 'gfh*' -exec bash -c 'echo mv $0 ${0/gfh/jkl}' {} \;
Чтобы установить скрипт переименования Perl:
sudo cpan install File::Rename
Есть два переименования, как указано в комментариях в ответе Stephan202. Дистрибутивы на основе Debian переименованы в Perl. Redhat/rpm дистрибутивы имеют C переименование.
OS X не имеет установленного по умолчанию (по крайней мере, в 10.8), равно как и Windows/Cygwin.
Вот способ сделать это с помощью командной строки Groovy:
groovy -e 'new File(".").eachFileMatch(~/fgh.*/) {it.renameTo(it.name.replaceFirst("fgh", "jkl"))}'
На Солярисе вы можете попробовать:
for file in `find ./ -name "*TextForRename*"`; do
mv -f "$file" "${file/TextForRename/NewText}"
done
Этот сценарий работал у меня для рекурсивного переименования с именами каталогов / файлов, возможно, содержащих пробелы:
find . -type f -name "*\;*" | while read fname; do
dirname=`dirname "$fname"`
filename=`basename "$fname"`
newname=`echo "$filename" | sed -e "s/;/ /g"`
mv "${dirname}/$filename" "${dirname}/$newname"
done
Обратите внимание на sed
выражение, которое в этом примере заменяет все вхождения ;
с пространством . Это, конечно, должно быть заменено в соответствии с конкретными потребностями.
#!/bin/sh
#replace all files ended witn .f77 to .f90 in a directory
for filename in *.f77
do
#echo $filename
#b= echo $filename | cut -d. -f1
#echo $b
mv "${filename}" "${filename%.f77}.f90"
done
Я бы порекомендовал использовать свой собственный скрипт, который решает эту проблему. У него также есть опции для изменения кодировки имен файлов и для преобразования комбинированных диакритических знаков в заранее составленные символы, проблема, с которой я всегда сталкиваюсь, когда копирую файлы с моего Mac.
Использование инструментов StringSolver (Windows & Linux Bash), которые обрабатываются на примерах:
filter fghfilea ok fghreport ok notfghfile notok; mv --all --filter fghfilea jklfilea
Сначала он вычисляет фильтр на основе примеров, где входными данными являются имена файлов и выходные данные (ok и notok, произвольные строки). Если бы фильтр имел опцию --auto или был вызван один после этой команды, он создал бы папку ok
и папка notok
и нажмите файлы соответственно им.
Затем с помощью фильтра mv
Команда - это полуавтоматическое движение, которое становится автоматическим с модификатором --auto. Используя предыдущий фильтр благодаря --filter, он находит отображение из fghfilea
в jklfilea
а затем применяет его ко всем отфильтрованным файлам.
Другие однолинейные решения
Другие эквивалентные способы сделать то же самое (каждая строка эквивалентна), так что вы можете выбрать свой любимый способ сделать это.
filter fghfilea ok fghreport ok notfghfile notok; mv --filter fghfilea jklfilea; mv
filter fghfilea ok fghreport ok notfghfile notok; auto --all --filter fghfilea "mv fghfilea jklfilea"
# Even better, automatically infers the file name
filter fghfilea ok fghreport ok notfghfile notok; auto --all --filter "mv fghfilea jklfilea"
Многошаговое решение
Чтобы тщательно определить, хорошо ли работают команды, вы можете набрать следующее:
filter fghfilea ok
filter fghfileb ok
filter fghfileb notok
и когда вы уверены, что фильтр хорош, выполните первый шаг:
mv fghfilea jklfilea
Если вы хотите проверить и использовать предыдущий фильтр, введите:
mv --test --filter
Если преобразование не то, что вы хотели (например, даже с mv --explain
Вы видите, что что-то не так), вы можете ввести mv --clear
перезапустить движущиеся файлы или добавить больше примеров mv input1 input2
где input1 и input2 - другие примеры
Когда вы уверены, просто введите
mv --filter
и вуаля! Все переименование осуществляется с помощью фильтра.
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я являюсь соавтором этой работы, созданной для академических целей. Возможно, скоро появится функция создания bash.
Используя renamer:
$ renamer --find /^fgh/ --replace jkl * --dry-run
Удалить --dry-run
Отметьте, когда вы довольны, результат выглядит правильно.
Моя версия переименования массовых файлов:
for i in *; do
echo "mv $i $i"
done |
sed -e "s#from_pattern#to_pattern#g” > result1.sh
sh result1.sh
Еще один возможный параметр расширения:
for f in fgh*; do mv -- "$f" "jkl${f:3}"; done
Это было намного проще (на моем Mac) сделать это в Ruby. Вот 2 примера:
# for your fgh example. renames all files from "fgh..." to "jkl..."
files = Dir['fgh*']
files.each do |f|
f2 = f.gsub('fgh', 'jkl')
system("mv #{f} #{f2}")
end
# renames all files in directory from "021roman.rb" to "021_roman.rb"
files = Dir['*rb'].select {|f| f =~ /^[0-9]{3}[a-zA-Z]+/}
files.each do |f|
f1 = f.clone
f2 = f.insert(3, '_')
system("mv #{f1} #{f2}")
end
Это расширенная версия решения +++.
Оригинальные решения: это и это .
Требования: поиск, обрезка, регулярное выражение, переименование
- Я хочу переименовать несколько файлов во многих папках.
- Некоторые папки должны быть удалены/исключены.
- я на
cygwin
и не могу получитьperl rename
для работы, что требуется для самого популярного решения (и я полагаю, что оно медленное, поскольку, похоже, у него нет возможности обрезки?)
Решение
- Использовать
find
для эффективного получения файлов (с обрезкой) и с множеством параметров настройки. - Используйте для замены регулярного выражения.
- Использовать
xargs
чтобы направить результат в окончательную команду.
Пример 1: переименовать*.js
файлы, но игнорировать
В этом примере выполняется поиск файлов и отображение найденного файла и переименованного файла. Из соображений безопасности он пока ничего не двигает. Вы должны заменить на для этого.
set -x # stop on error
set -e # verbose mode (echo all commands)
find "." -type f -not \( -path "**/node_modules/**" -prune \) -name "*.js" |
sed -nE "s/(.*)\/my(.*)/& \1\/YOUR\2/p" |
xargs -n 2 echo # echo first (replace with `mv` later)
Приведенный выше скрипт превращает это:
./x/y/my-abc.js
В это:
./x/y/YOUR-abc.js
Разбивка решения
-
find "." -type f -not \( -path "**/node_modules/**" -prune \) -name "*.js"
- Ищет файлы (
-type f
). - The
-not
часть исключает (и, что важно, не пересекает!)node_modules
папка. - Имя файла должно совпадать
"*.js"
. - Вы можете добавить дополнительные пункты включения и исключения.
- Ссылки:
- В этом посте обсуждаются альтернативы рекурсивному поиску файлов.
- В этом посте обсуждаются аспекты обрезки и исключения.
- мужчина находит
- Ищет файлы (
-
sed -nE "s/(.*)\/my\-(.*\.js)/& \1\/YOUR-\2/p"
- ПРИМЕЧАНИЕ: всегда нужно привыкнуть.
-
-E
включает "расширенный" (т.е. более современный) синтаксис регулярных выражений. - используется в сочетании с завершающим флагом:
-n
скрывает все результаты, а/p
напечатает только совпадающие результаты. Таким образом, мы видим/перемещаем только те файлы, которые необходимо изменить, и игнорируем все остальные. - Замена регулярного выражения на
sed
(и другие инструменты регулярных выражений) всегда имеет формат:s/regex/replacement/FLAGS
- Взамен,
&
представляет совпадающую входную строку. Это будет первым аргументомmv
. - Ссылки:
-
xargs -n 2 echo
- Запустите команду
echo
с (первыми двумя строками) замененной строки. - Ссылки: человек xargs
- Запустите команду
Удачи!
Общий скрипт для запуска sed
Выражение в списке файлов (объединяет sed
Решение с rename
решение):
#!/bin/sh
e=$1
shift
for f in $*; do
fNew=$(echo "$f" | sed "$e")
mv "$f" "$fNew";
done
Вызвать, передав скрипт sed
выражение, а затем любой список файлов, так же, как версия rename
:
script.sh 's/^fgh/jkl/' fgh*
Я написал этот скрипт для поиска всех файлов.mkv, рекурсивно переименовывая найденные файлы в.avi. Вы можете настроить его под свои нужды. Я добавил некоторые другие вещи, такие как получение файлового каталога, расширения, имени файла из пути к файлу, только в том случае, если вам понадобится обратиться к чему-то в будущем.
find . -type f -name "*.mkv" | while read fp; do
fd=$(dirname "${fp}");
fn=$(basename "${fp}");
ext="${fn##*.}";
f="${fn%.*}";
new_fp="${fd}/${f}.avi"
mv -v "$fp" "$new_fp"
done;
Это сработало для меня с помощью регулярных выражений:
Я хотел, чтобы файлы были переименованы так:
file0001.txt -> 1.txt
ofile0002.txt -> 2.txt
f_i_l_e0003.txt -> 3.txt
usig регулярное выражение [az | _] + 0 * ([0-9] +.), где ([0-9] +.) - подстрока группы для использования в команде переименования.
ls -1 | awk 'match($0, /[a-z|\_]+0*([0-9]+.*)/, arr) { print arr[0] " " arr[1] }'|xargs -l mv
Производит:
mv file0001.txt 1.txt
mv ofile0002.txt 2.txt
mv f_i_l_e0003.txt 3.txt
Другой пример:
file001abc.txt -> abc1.txt
ofile0002abcd.txt -> abcd2.txt
ls -1 | awk 'match($0, /[a-z|\_]+0*([0-9]+.*)([a-z]+)/, arr) { print arr[0] " " arr[2] arr[1] }'|xargs -l mv
Производит:
mv file001abc.txt abc1.txt
mv ofile0002abcd.txt abcd2.txt
Предупреждение, будь осторожен.
Этот ответ представляет собой лишь конкретное применение того, что объяснено в других ответах, я надеюсь, что он будет полезен:
Я столкнулся с случаем, когда мне пришлось переименовать некоторые файлы свойств, которые имели формуCodeAPE_fr.properties
кCodeAPE.properties
, во всем каталоге, и я сделал:
for i in `dir`; do mv $i `echo $i | sed 's/_fr.properties/.properties/g'`; done
Вот небольшое улучшение/корректировка, которая вам понадобится, если имена файлов содержат пробелы И вы хотите фильтровать на основе части имени файла, которая имеет шаблон с пробелами:
for f in "Filename With Spaces"*; do mv "$f" "$(echo $f | sed 's/^Filename With Spaces/FilenameWithNoMoreSpaces/g')"; done
Ключевое отличие в моем ответе заключается в том, что вам нужно заключить в кавычки «Имя файла с пробелами», если это часть имени файла, которую вы хотите использовать в качестве фильтра для выбора файлов, с которыми нужно работать. В предыдущих ответах имя файла упоминалось с пробелами, но затем были выбраны файлы на основе jkl*, в котором нет пробелов.
Примечание. Заменять на FilenameWithNoMoreSpaces не обязательно. Я просто хотел показать типичный вариант использования в качестве примера.
Если шаблон с пробелом находится в СЕРЕДИНЕ имени файла, то измененная команда будет следовать следующему шаблону:
for f in *"Spaces In Middle of Filename"*; do mv "$f" "$(echo $f | sed 's/Spaces In Middle of Filename/FilenameWithNoMoreSpaces/g')"; done
Обратите внимание: я добавил еще одну звездочку в начало шаблона имени файла с пробелами в двойных кавычках и удалил карат ^ из части «найти» команды sed. Мои извинения, если я слишком объясняю. Я принимаю во внимание, что некоторые люди, читающие это, могут быть совершенно новичками в программировании.
Вы также можете использовать приведенный ниже скрипт. на терминале очень легко бегать...
// Переименование нескольких файлов одновременно
for file in FILE_NAME*
do
mv -i "${file}" "${file/FILE_NAME/RENAMED_FILE_NAME}"
done
Пример:-
for file in hello*
do
mv -i "${file}" "${file/hello/JAISHREE}"
done