Chúng ta có thể giả định sed
có sẵn trên bất kỳ * nix, nhưng chúng tôi không thể chắc chắn nó sẽ hỗ trợ sed -n
để tạo lệnh mv. (LƯU Ý: Chỉ GNU sed
thực hiện điều này.)
Mặc dù vậy, bash xây dựng và sed, chúng ta có thể nhanh chóng roi lên một hàm vỏ để làm điều này.
sedrename() {
if [ $# -gt 1 ]; then
sed_pattern=$1
shift
for file in $(ls [email protected]); do
mv -v "$file" "$(sed $sed_pattern <<< $file)"
done
else
echo "usage: $0 sed_pattern files..."
fi
}
Cách sử dụng
sedrename 's|\(.*\)\(-[0-9.]*\.pkg\)|\1\2|' *.pkg
before:
./Xft2-2.1.13.pkg
./jasper-1.900.1.pkg
./xorg-libXrandr-1.2.3.pkg
after:
./Xft2.pkg
./jasper.pkg
./xorg-libXrandr.pkg
Tạo thư mục mục tiêu:
Kể từ mv
không tự động tạo thư mục mục tiêu chúng ta không thể sử dụng phiên bản ban đầu của chúng ta về sedrename
.
Đó là một sự thay đổi khá nhỏ, vì vậy nó sẽ được tốt đẹp để bao gồm tính năng:
Chúng tôi sẽ cần một chức năng tiện ích, abspath
(hoặc đường dẫn tuyệt đối) từ bash không có build này.
abspath() { case "$1" in
/*)printf "%s\n" "$1";;
*)printf "%s\n" "$PWD/$1";;
esac; }
một khi chúng ta có mà chúng ta có thể tạo ra các thư mục đích (s) cho một sed/đổi tên mẫu trong đó bao gồm cấu trúc thư mục mới.
Điều này sẽ đảm bảo chúng tôi biết tên của các thư mục đích của chúng tôi. Khi chúng tôi đổi tên, chúng tôi sẽ cần sử dụng nó trên tên tệp đích.
# generate the rename target
target="$(sed $sed_pattern <<< $file)"
# Use absolute path of the rename target to make target folder structure
mkdir -p "$(dirname $(abspath $target))"
# finally move the file to the target name/folders
mv -v "$file" "$target"
Dưới đây là thư mục kịch bản đầy đủ ý thức ...
sedrename() {
if [ $# -gt 1 ]; then
sed_pattern=$1
shift
for file in $(ls [email protected]); do
target="$(sed $sed_pattern <<< $file)"
mkdir -p "$(dirname $(abspath $target))"
mv -v "$file" "$target"
done
else
echo "usage: $0 sed_pattern files..."
fi
}
Tất nhiên, nó vẫn hoạt động khi chúng ta không có mục tiêu cụ thể thư mục quá.
Nếu chúng ta muốn đặt tất cả các bài hát vào một thư mục, ./Beethoven/
chúng ta có thể làm điều này:
Cách sử dụng
sedrename 's|Beethoven - |Beethoven/|g' *.mp3
before:
./Beethoven - Fur Elise.mp3
./Beethoven - Moonlight Sonata.mp3
./Beethoven - Ode to Joy.mp3
./Beethoven - Rage Over the Lost Penny.mp3
after:
./Beethoven/Fur Elise.mp3
./Beethoven/Moonlight Sonata.mp3
./Beethoven/Ode to Joy.mp3
./Beethoven/Rage Over the Lost Penny.mp3
Bonus tròn ...
Sử dụng kịch bản này để di chuyển file từ các thư mục vào một thư mục:
Giả sử chúng tôi muốn tập hợp tất cả các tệp phù hợp và đặt chúng trong f hiện tại già đi, chúng ta có thể làm điều đó:
sedrename 's|.*/||' **/*.mp3
before:
./Beethoven/Fur Elise.mp3
./Beethoven/Moonlight Sonata.mp3
./Beethoven/Ode to Joy.mp3
./Beethoven/Rage Over the Lost Penny.mp3
after:
./Beethoven/ # (now empty)
./Fur Elise.mp3
./Moonlight Sonata.mp3
./Ode to Joy.mp3
./Rage Over the Lost Penny.mp3
Lưu ý về mẫu regex sed
Regular quy tắc mẫu sed áp dụng trong kịch bản này, các mẫu không PCRE (Regular Expressions Perl Tương thích). Bạn có thể có sed cú pháp biểu thức chính quy mở rộng, sử dụng sed -r
hoặc sed -E
tùy thuộc vào nền tảng của bạn.
Xem POSIX tuân thủ man re_format
để có mô tả đầy đủ về sed mẫu regexp cơ bản và mở rộng.
Tôi định sử dụng thường xuyên, như một tập lệnh dùng một lần. Bất kỳ hệ thống nào tôi sẽ sử dụng đều sẽ bị bash, vì vậy tôi không sợ các bashism khá tiện dụng. –
Thông thường, xem thêm https://stackoverflow.com/questions/28725333/looping-over-pairs-of-values-in-bash – tripleee