Có nhiều tệp trong một thư mục bắt đầu bằng tiền tố fgh
, ví dụ:
fghfilea
fghfileb
fghfilec
Tôi muốn đổi tên tất cả chúng để bắt đầu bằng tiền tố jkl
. Có một lệnh duy nhất để làm điều đó thay vì đổi tên từng tệp riêng lẻ không?
Có nhiều tệp trong một thư mục bắt đầu bằng tiền tố fgh
, ví dụ:
fghfilea
fghfileb
fghfilec
Tôi muốn đổi tên tất cả chúng để bắt đầu bằng tiền tố jkl
. Có một lệnh duy nhất để làm điều đó thay vì đổi tên từng tệp riêng lẻ không?
Câu trả lời:
Có một số cách, nhưng sử dụng rename
có thể sẽ là dễ nhất.
Sử dụng một phiên bản của rename
:
rename 's/^fgh/jkl/' fgh*
Sử dụng phiên bản khác của rename
(giống như câu trả lời của Judy2K ):
rename fgh jkl fgh*
Bạn nên kiểm tra trang người dùng của nền tảng của bạn để xem áp dụng nào ở trên.
rename
thì bạn đang hiển thị cú pháp cho unixhelp.ed.ac.uk/CGI/man-cgi?rename là một cái khác
rename
dường như là một tập lệnh hoặc tiện ích cụ thể của Linux. Nếu bạn quan tâm đến tính di động, vui lòng tiếp tục sử dụng sed
và các vòng lặp hoặc tập lệnh Perl nội tuyến.
brew install rename
trên OS X :)
Đây là cách sed
và mv
có thể được sử dụng cùng nhau để đổi tên:
for f in fgh*; do mv "$f" $(echo "$f" | sed 's/^fgh/jkl/g'); done
Theo nhận xét bên dưới, nếu tên tệp có khoảng trắng trong đó, dấu ngoặc kép có thể cần bao quanh hàm phụ trả về tên để di chuyển tệp đến:
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
. Tôi vui lòng đề nghị xem xét nhận xét @DaveNelson.
đổi tên có thể không có trong mọi hệ thống. Vì vậy, nếu bạn không có nó, hãy sử dụng shell ví dụ này trong bash shell
for f in fgh*; do mv "$f" "${f/fgh/xxx}";done
sed
lệnh không bắt buộc. Câu hỏi này đơn giản hơn câu trả lời của @ nik.
sh
hoặc nói chung trong các shell khác.
Sử dụng mmv :
mmv "fgh*" "jkl#1"
;
kết hợp với #1
. ví dụ:mmv ";fgh*" "#1jkl#2"
Có nhiều cách để làm điều đó (không phải tất cả trong số này sẽ hoạt động trên tất cả các hệ thống unixy):
ls | cut -c4- | xargs -I§ mv fgh§ jkl§
§ có thể được thay thế bởi bất cứ điều gì bạn thấy thuận tiện. Bạn cũng có thể làm điều này find -exec
nhưng nó hoạt động khác biệt tinh tế trên nhiều hệ thống, vì vậy tôi thường tránh điều đó
for f in fgh*; do mv "$f" "${f/fgh/jkl}";done
Thô lỗ nhưng hiệu quả như họ nói
rename 's/^fgh/jkl/' fgh*
Thực sự đẹp, nhưng đổi tên không có trên BSD, đây là hệ thống unix phổ biến nhất afaik.
rename fgh jkl fgh*
ls | perl -ne 'chomp; next unless -e; $o = $_; s/fgh/jkl/; next if -e; rename $o, $_';
Nếu bạn khăng khăng sử dụng Perl, nhưng không có đổi tên trên hệ thống của bạn, bạn có thể sử dụng quái vật này.
Một số trong số đó là một chút phức tạp và danh sách không đầy đủ, nhưng bạn sẽ tìm thấy những gì bạn muốn ở đây cho hầu hết các hệ thống unix.
rename fgh jkl fgh*
Sử dụng find
, xargs
và sed
:
find . -name "fgh*" -type f -print0 | xargs -0 -I {} sh -c 'mv "{}" "$(dirname "{}")/`echo $(basename "{}") | sed 's/^fgh/jkl/g'`"'
Nó phức tạp hơn giải pháp của @ nik nhưng nó cho phép đổi tên các tệp theo cách đệ quy. Ví dụ, cấu trúc,
.
├── fghdir
│ ├── fdhfilea
│ └── fghfilea
├── fghfile\ e
├── fghfilea
├── fghfileb
├── fghfilec
└── other
├── fghfile\ e
├── fghfilea
├── fghfileb
└── fghfilec
sẽ được chuyển đổi sang đây
.
├── fghdir
│ ├── fdhfilea
│ └── jklfilea
├── jklfile\ e
├── jklfilea
├── jklfileb
├── jklfilec
└── other
├── jklfile\ e
├── jklfilea
├── jklfileb
└── jklfilec
Chìa khóa để làm cho nó hoạt động xargs
là gọi shell từ xargs .
Để cài đặt tập lệnh đổi tên Perl :
sudo cpan install File::Rename
Có hai sự đổi tên như được đề cập trong các bình luận trong câu trả lời của Stephan202. Các bản phân phối dựa trên Debian có đổi tên Perl . Các bản phân phối Redhat / vòng / phút có tên C đổi tên .
OS X không có cài đặt mặc định (ít nhất là trong 10.8), Windows / Cygwin cũng không.
Đây là một cách để làm điều đó bằng cách sử dụng dòng lệnh Groovy:
groovy -e 'new File(".").eachFileMatch(~/fgh.*/) {it.renameTo(it.name.replaceFirst("fgh", "jkl"))}'
Trên Solaris bạn có thể thử:
for file in `find ./ -name "*TextForRename*"`; do
mv -f "$file" "${file/TextForRename/NewText}"
done
for file in $(find)
về cơ bản là thiếu sót và không thể sửa chữa bằng trích dẫn. Nếu find
lợi nhuận ./file name with spaces
bạn sẽ nhận được một for
vòng lặp qua ./file
, name
, with
, và spaces
và không có số lượng trích dẫn bên trong vòng lặp sẽ giúp (hoặc thậm chí là cần thiết).
Kịch bản này hoạt động với tôi để đổi tên đệ quy với các thư mục / tên tệp có thể chứa khoảng trắng:
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
Lưu ý sed
biểu thức trong ví dụ này thay thế tất cả các lần xuất hiện ;
với không gian . Điều này tất nhiên nên được thay thế theo nhu cầu cụ thể.
Sử dụng các công cụ StringSolver (bash windows & Linux) xử lý bằng các ví dụ:
filter fghfilea ok fghreport ok notfghfile notok; mv --all --filter fghfilea jklfilea
Đầu tiên, nó tính toán một bộ lọc dựa trên các ví dụ , trong đó đầu vào là tên tệp và đầu ra (ok và notok, các chuỗi tùy ý). Nếu bộ lọc có tùy chọn --auto hoặc được gọi một mình sau lệnh này, nó sẽ tạo một thư mục ok
và thư mục notok
và đẩy các tệp tương ứng với chúng.
Sau đó, sử dụng bộ lọc, mv
lệnh là một bước di chuyển bán tự động trở thành tự động với công cụ sửa đổi --auto. Sử dụng bộ lọc trước nhờ vào --filter, nó tìm thấy ánh xạ từ fghfilea
đến jklfilea
và sau đó áp dụng nó trên tất cả các tệp được lọc.
Các giải pháp một dòng khác
Các cách tương đương khác để làm tương tự (mỗi dòng là tương đương), vì vậy bạn có thể chọn cách làm yêu thích của mình.
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"
Giải pháp nhiều bước
Để cẩn thận tìm xem các lệnh có hoạt động tốt không, bạn có thể gõ như sau:
filter fghfilea ok
filter fghfileb ok
filter fghfileb notok
và khi bạn tự tin rằng bộ lọc tốt, hãy thực hiện bước đầu tiên:
mv fghfilea jklfilea
Nếu bạn muốn kiểm tra và sử dụng bộ lọc trước đó, hãy nhập:
mv --test --filter
Nếu chuyển đổi không phải là điều bạn muốn (ví dụ: ngay cả khi mv --explain
bạn thấy có gì đó không đúng), bạn có thể nhập mv --clear
để khởi động lại các tệp đang di chuyển hoặc thêm các ví dụ khácmv input1 input2
trong đó input1 và input2 là các ví dụ khác
Khi bạn tự tin, chỉ cần gõ
mv --filter
và Voila! Tất cả việc đổi tên được thực hiện bằng bộ lọc.
TUYÊN BỐ TỪ CHỐI: Tôi là đồng tác giả của tác phẩm này được thực hiện cho mục đích học tập. Cũng có thể có một tính năng sản xuất bash sớm.
Nó dễ dàng hơn nhiều (trên máy Mac của tôi) để làm điều này trong Ruby. Dưới đây là 2 ví dụ:
# 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
Phiên bản đổi tên tập tin đại chúng của tôi:
for i in *; do
echo "mv $i $i"
done |
sed -e "s#from_pattern#to_pattern#g” > result1.sh
sh result1.sh
Tôi sẽ khuyên bạn nên sử dụng kịch bản của riêng tôi, giải quyết vấn đề này. Nó cũng có các tùy chọn để thay đổi mã hóa tên tệp và để chuyển đổi kết hợp dấu phụ sang các ký tự được phân tách trước, một vấn đề tôi luôn gặp phải khi sao chép tệp từ máy 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
Điều này làm việc cho tôi bằng cách sử dụng regrec:
Tôi muốn các tập tin được đổi tên như thế này:
file0001.txt -> 1.txt
ofile0002.txt -> 2.txt
f_i_l_e0003.txt -> 3.txt
usig, [az | _] + 0 * ([0-9] +. ) regrec trong đó ([0-9] +. ) là một chuỗi con nhóm để sử dụng trên lệnh đổi tên
ls -1 | awk 'match($0, /[a-z|\_]+0*([0-9]+.*)/, arr) { print arr[0] " " arr[1] }'|xargs -l mv
Sản xuất:
mv file0001.txt 1.txt
mv ofile0002.txt 2.txt
mv f_i_l_e0003.txt 3.txt
Một vi dụ khac:
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
Sản xuất:
mv file001abc.txt abc1.txt
mv ofile0002abcd.txt abcd2.txt
Cảnh báo, cẩn thận.
Tôi đã viết tập lệnh này để tìm kiếm tất cả các tệp .mkv đệ quy đổi tên các tệp tìm thấy thành .avi. Bạn có thể tùy chỉnh nó để bạn có. Tôi đã thêm một số thứ khác như nhận thư mục tệp, phần mở rộng, tên tệp từ đường dẫn tệp chỉ cần bạn cần tham khảo một cái gì đó trong tương lai.
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;
Một tập lệnh chung để chạy một sed
biểu thức trên danh sách các tệp (kết hợp sed
giải pháp với rename
giải pháp ):
#!/bin/sh
e=$1
shift
for f in $*; do
fNew=$(echo "$f" | sed "$e")
mv "$f" "$fNew";
done
Gọi bằng cách chuyển tập lệnh một sed
biểu thức và sau đó bất kỳ danh sách tệp nào, giống như một phiên bản của rename
:
script.sh 's/^fgh/jkl/' fgh*
Bạn cũng có thể sử dụng kịch bản dưới đây. nó rất dễ chạy trên thiết bị đầu cuối ...
// Đổi tên nhiều tệp cùng một lúc
for file in FILE_NAME*
do
mv -i "${file}" "${file/FILE_NAME/RENAMED_FILE_NAME}"
done
Thí dụ:-
for file in hello*
do
mv -i "${file}" "${file/hello/JAISHREE}"
done
Một mở rộng tham số có thể khác :
for f in fgh*; do mv -- "$f" "jkl${f:3}"; done