Có một số vấn đề với kịch bản của bạn.
for x in 'ls'
Bạn đang lặp lại một danh sách chứa một từ : ls
. Bạn có thể có nghĩa là để viết `ls`
(với backticks), để phân tích đầu ra của ls
. Không phân tích đầu ra củals
: điều này sẽ không hoạt động nếu tên tệp chứa các ký tự đặc biệt như khoảng trắng. Shell đã có sẵn một cách liệt kê các tệp trong một thư mục: ký tự đại diện. Vì vậy, viết for x in *
.
if [ ! -f $x ]; then
Điều này sẽ không hoạt động nếu tên tệp chứa khoảng trắng và các ký tự đặc biệt khác, bởi vì khi bạn viết $x
dấu ngoặc kép bên ngoài, kết quả được chia thành các từ riêng biệt (và mỗi từ được hiểu là một mẫu ký tự đại diện, để khởi động). Để tránh hiệu ứng này, hãy đặt $x
trong dấu ngoặc kép : if [ ! -f "$x" ]; then
. Bạn có thể nhớ các quy tắc phức tạp hoặc chỉ luôn luôn sử dụng dấu ngoặc kép xung quanh các thay thế khác nhau.
Một số dòng khác bị hỏng do thiếu dấu ngoặc kép. Chỉ cần đặt chúng xung quanh mỗi thay thế biến.
lc = `echo $x | tr '[A-Z]' '[a-z]'`
Điều này sẽ không hoạt động do các khoảng trắng xung quanh dấu bằng: dòng này thực thi lc
lệnh, chuyển nó =
làm đối số đầu tiên (và các đối số khác). Một bài tập trong shell phải không có khoảng trắng xung quanh =
dấu.
Bạn không cần dấu ngoặc quanh các đối số của tr
. Đây là lệnh xảy ra với công việc bởi vì bạn đang nói để thay thế [
bằng [
và ]
bằng cách ]
thêm vào các lowercasing.
Tôi khuyên bạn nên sử dụng dấu ngoặc đơn $(…)
thay vì backticks `…`
để thay thế lệnh. Chúng tương đương nhau, ngoại trừ việc backticks có các quy tắc phức tạp khi trích dẫn những thứ bên trong nó, trong khi $(…)
có một cú pháp rất trực quan. Nói chung, lệnh đó phải là:lc=$(echo "$x" | tr A-Z a-z)
find -name "* *" -type f | rename 's/ /-/g'
Thông báo lỗi của bạn cho thấy rằng bạn có rename
lệnh từ gói linux-linux chứ không phải tập lệnh Perl được tìm thấy trên Debian và các công cụ phái sinh (bao gồm cả Ubuntu). Cú pháp bạn sử dụng chỉ có ý nghĩa với tập lệnh Perl.
Nếu bạn sẽ sử dụng tập lệnh Perl, nó có thể thay đổi trường hợp thành chữ thường, vì vậy bạn không cần phải làm điều đó trước. Và bạn không cần phải gọi find
trừ khi bạn muốn đổi tên các tệp trong thư mục con (phần đầu tiên của bạn không xử lý). Nếu bạn muốn đổi tên tất cả các tệp trong thư mục hiện tại, bạn chỉ cần viết:
prename 'tr/A-Z /a-z-/' -- *
Nếu bạn chỉ muốn đổi tên các tệp thông thường (nhưng không phải thư mục con, liên kết tượng trưng, v.v.), hãy sử dụng find
:
find . -type f -maxdepth 1 -exec prename 'tr/A-Z /a-z-/' {} +
Nếu bạn cũng muốn hành động trên các tệp trong thư mục con và tên thư mục có thể chứa dấu cách hoặc chữ in hoa, bạn phải cẩn thận để chúng một mình. Vì bạn đang dùng Linux, bạn có thể sử dụng -execdir
để gọi prename
với một đối số không chứa tên thư mục.
find . -type f -execdir prename 'tr/A-Z /a-z-/' {} +
Nếu bạn không có rename
tiện ích Perl thì sao? Tiện ích linux-linux rename
sẽ không giúp bạn ở đây. Bạn có thể đặt thêm một thay thế trong vòng lặp của bạn.
for x in ./*; do
if [ -f "$x" ]; then
y=$(echo "$x" | tr 'A-Z-' 'a-z ')
mv "$x" "$y"
fi
done
Với bash, bạn không cần gọi tr
, bạn có thể sử dụng các cấu trúc thay thế chuỗi của nó.
for x in ./*; do
if [ -f "$x" ]; then
lc=${x,,} # convert all letters to lowercase
y=${lc// /-} # replace spaces by hyphens
if [ "$x" != "$y" ]; then
mv "$x" "$y"
fi
fi
done
Nếu bạn cũng muốn hành động trên các tệp trong thư mục con, bạn có thể sử dụng một quả cầu đệ quy (được bật bởi globstar
tùy chọn). Một lần nữa, hãy cẩn thận để lại phần thư mục nếu chúng có thể chứa các chữ cái hoặc dấu cách.
shopt -s globstar
for x in ./**/*; do
if [ -f "$x" ]; then
old_basename=${x##*/}
new_basename=${old_basename,,}
new_basename=${new_basename// /-}
if [ "$new_basename" != "$old_basename" ]; then
mv "${x%/*}/$old_basename" "${x%/*}/$new_basename"
fi
fi
done
Trong zsh, đặt autoload -U zmv
vào của bạn .zshrc
và bạn có thể sử dụng zmv
với vòng loại toàn cầu .
để chỉ khớp với các tệp thông thường và cấu trúc mở rộng tham số cho việc đổi tên:
zmv -Q '*(.)' '${(L)f// /-}'
Để hành động trên các tệp trong thư mục con là tốt:
zmv -Qw '**/*(.)' '$1${(L)2// /-}'
mv
và ném vào mộtecho $lc
hoặc hai để bạn có thể thấy những gì bạn đang làm, sau đó làm việc từ đó? Xem thêmbash -x
: tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_03.html Học cách câu cá tốt hơn là yêu cầu cá;)