У каталозі є кілька файлів, які починаються з префікса fgh
, наприклад:
fghfilea
fghfileb
fghfilec
Я хочу перейменувати їх усіх, щоб почати з префікса jkl
. Чи є одна команда зробити це замість перейменування кожного файлу окремо?
У каталозі є кілька файлів, які починаються з префікса fgh
, наприклад:
fghfilea
fghfileb
fghfilec
Я хочу перейменувати їх усіх, щоб почати з префікса jkl
. Чи є одна команда зробити це замість перейменування кожного файлу окремо?
Відповіді:
Є кілька способів, але використовувати rename
, мабуть, буде найпростіше.
Використання однієї версії rename
:
rename 's/^fgh/jkl/' fgh*
Використовуючи іншу версію rename
(те саме , що відповідь Judy2K ):
rename fgh jkl fgh*
Перевірте головну сторінку вашої платформи, щоб побачити, що з вищезазначеного застосовується.
rename
тоді ви показуєте синтаксис unixhelp.ed.ac.uk/CGI/man-cgi?rename є іншим
rename
здається, є специфічним для Linux сценарієм або утилітою. Якщо ви взагалі переймаєтесь портативністю, продовжуйте використовувати sed
і циклічні вбудовані сценарії Perl.
brew install rename
на OS X :)
Ось як це можна 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
for f in fgh*; do mv "$f" "$(echo $f | sed 's/^fgh/jkl/g')"; done
touch fghfilea fghfileb fghfilec fghfile\ d
. Я пропоную врахувати зауваження @DaveNelson.
перейменування може бути не в кожній системі. тож якщо у вас його немає, використовуйте цей приклад у bash shell
for f in fgh*; do mv "$f" "${f/fgh/xxx}";done
sed
команда не потрібна. Цей простіший, ніж відповідь @ nik.
sh
або взагалі в інших оболонках.
Використання mmv :
mmv "fgh*" "jkl#1"
;
спільно з #1
. Приклад:mmv ";fgh*" "#1jkl#2"
Існує багато способів зробити це (не всі вони будуть працювати на всіх системах 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, яка є найпоширенішою системою afaik Unix.
rename fgh jkl fgh*
ls | perl -ne 'chomp; next unless -e; $o = $_; s/fgh/jkl/; next if -e; rename $o, $_';
Якщо ви наполягаєте на використанні Perl, але у вашій системі немає перейменування, ви можете використовувати цього монстра.
Деякі з них дещо заплутані, і перелік далеко не повний, але ви знайдете те, що хочете тут, майже для всіх Unix систем.
rename fgh jkl fgh*
Використання 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 .
Щоб встановити сценарій перейменування Perl :
sudo cpan install File::Rename
Є два перейменування, як згадується у коментарях у відповіді Стефана202. Дистрибутиви на основі 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"))}'
На Solaris ви можете спробувати:
for file in `find ./ -name "*TextForRename*"`; do
mv -f "$file" "${file/TextForRename/NewText}"
done
for file in $(find)
це принципово хибно і не може бути виправлено цитуванням. Якщо find
повертається ./file name with spaces
ви отримаєте for
петлю на ./file
, name
, with
і spaces
та ніяке кількість квотування всередині циклу допоможе (або навіть необхідно).
Цей сценарій працював для мене для рекурсивного перейменування з іменами каталогів / файлів, можливо, містять пробіли:
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
вираз, який у цьому прикладі замінює всі випадки ;
пробілу . Звичайно, це слід замінити відповідно до конкретних потреб.
Використання інструментів 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
і voilà! Все перейменування проводиться за допомогою фільтра.
ВІДМОВА: Я є співавтором цього твору, зробленого в академічних цілях. Невдовзі також може з’явитися функція, що виробляє башти.
Це було набагато простіше (на моєму Mac) зробити це в Ruby. Ось два приклади:
# 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
Використання перейменування :
$ 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
Я б рекомендував використовувати власний сценарій, який вирішує цю проблему. У ньому також є можливості змінити кодування імен файлів і перетворити комбінуючі діакритики на заздалегідь складені символи - проблема, яку я завжди маю, коли копіюю файли з мого Mac.
#!/usr/bin/perl
# Copyright (c) 2014 André von Kugland
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
$help_msg =
"rename.pl, a script to rename files in batches, using Perl
expressions to transform their names.
Usage:
rename.pl [options] FILE1 [FILE2 ...]
Where options can be:
-v Verbose.
-vv Very verbose.
--apply Really apply modifications.
-e PERLCODE Execute PERLCODE. (e.g. 's/a/b/g')
--from-charset=CS Source charset. (e.g. \"iso-8859-1\")
--to-charset=CS Destination charset. (e.g. \"utf-8\")
--unicode-normalize=NF Unicode normalization form. (e.g. \"KD\")
--basename Modifies only the last element of the path.
";
use Encode;
use Getopt::Long;
use Unicode::Normalize 'normalize';
use File::Basename;
use I18N::Langinfo qw(langinfo CODESET);
Getopt::Long::Configure ("bundling");
# ----------------------------------------------------------------------------------------------- #
# Our variables. #
# ----------------------------------------------------------------------------------------------- #
my $apply = 0;
my $verbose = 0;
my $help = 0;
my $debug = 0;
my $basename = 0;
my $unicode_normalize = "";
my @scripts;
my $from_charset = "";
my $to_charset = "";
my $codeset = "";
# ----------------------------------------------------------------------------------------------- #
# Get cmdline options. #
# ----------------------------------------------------------------------------------------------- #
$result = GetOptions ("apply" => \$apply,
"verbose|v+" => \$verbose,
"execute|e=s" => \@scripts,
"from-charset=s" => \$from_charset,
"to-charset=s" => \$to_charset,
"unicode-normalize=s" => \$unicode_normalize,
"basename" => \$basename,
"help|h|?" => \$help,
"debug" => \$debug);
# If not going to apply, then be verbose.
if (!$apply && $verbose == 0) {
$verbose = 1;
}
if ((($#scripts == -1)
&& (($from_charset eq "") || ($to_charset eq ""))
&& $unicode_normalize eq "")
|| ($#ARGV == -1) || ($help)) {
print $help_msg;
exit(0);
}
if (($to_charset ne "" && $from_charset eq "")
||($from_charset eq "" && $to_charset ne "")
||($to_charset eq "" && $from_charset eq "" && $unicode_normalize ne "")) {
$codeset = langinfo(CODESET);
$to_charset = $codeset if $from_charset ne "" && $to_charset eq "";
$from_charset = $codeset if $from_charset eq "" && $to_charset ne "";
}
# ----------------------------------------------------------------------------------------------- #
# Composes the filter function using the @scripts array and possibly other options. #
# ----------------------------------------------------------------------------------------------- #
$f = "sub filterfunc() {\n my \$s = shift;\n";
$f .= " my \$d = dirname(\$s);\n my \$s = basename(\$s);\n" if ($basename != 0);
$f .= " for (\$s) {\n";
$f .= " $_;\n" foreach (@scripts); # Get scripts from '-e' opt. #
# Handle charset translation and normalization.
if (($from_charset ne "") && ($to_charset ne "")) {
if ($unicode_normalize eq "") {
$f .= " \$_ = encode(\"$to_charset\", decode(\"$from_charset\", \$_));\n";
} else {
$f .= " \$_ = encode(\"$to_charset\", normalize(\"$unicode_normalize\", decode(\"$from_charset\", \$_)));\n"
}
} elsif (($from_charset ne "") || ($to_charset ne "")) {
die "You can't use `from-charset' nor `to-charset' alone";
} elsif ($unicode_normalize ne "") {
$f .= " \$_ = encode(\"$codeset\", normalize(\"$unicode_normalize\", decode(\"$codeset\", \$_)));\n"
}
$f .= " }\n";
$f .= " \$s = \$d . '/' . \$s;\n" if ($basename != 0);
$f .= " return \$s;\n}\n";
print "Generated function:\n\n$f" if ($debug);
# ----------------------------------------------------------------------------------------------- #
# Evaluates the filter function body, so to define it in our scope. #
# ----------------------------------------------------------------------------------------------- #
eval $f;
# ----------------------------------------------------------------------------------------------- #
# Main loop, which passes names through filters and renames files. #
# ----------------------------------------------------------------------------------------------- #
foreach (@ARGV) {
$old_name = $_;
$new_name = filterfunc($_);
if ($old_name ne $new_name) {
if (!$apply or (rename $old_name, $new_name)) {
print "`$old_name' => `$new_name'\n" if ($verbose);
} else {
print "Cannot rename `$old_name' to `$new_name'.\n";
}
} else {
print "`$old_name' unchanged.\n" if ($verbose > 1);
}
}
stale over time
Це працювало для мене за допомогою regexp:
Я хотів, щоб файли були перейменовані так:
file0001.txt -> 1.txt
ofile0002.txt -> 2.txt
f_i_l_e0003.txt -> 3.txt
usig [az | _] + 0 * ([0-9] +. ) regexp де ([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
Попередження, будьте обережні.
Я написав цей скрипт, щоб шукати всі .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;
Універсальний скрипт для запуску 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*
Ви також можете використовувати сценарій нижче. запустити на терміналі дуже просто ...
// Перейменуйте кілька файлів одночасно
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
Ще одне можливе розширення параметра :
for f in fgh*; do mv -- "$f" "jkl${f:3}"; done