Làm cách nào để thay thế khoảng trắng trong tất cả các tên tệp bằng dấu gạch dưới trong Linux bằng shell script?


16

Tôi đã thử theo kịch bản shell sẽ thay thế khoảng trắng từ tất cả tên tệp xml

for xml_file in $(find $1 -name "* .xml" -type f);
do
 echo "removing spaces from XML file:" $xml_file
 mv "$xml_file" "${xml_file// /_}";
done

Giả sử, tôi có tệp xml với tên xy z.xml, sau đó nó cung cấp:

removing spaces from XML file: /home/krishna/test/xy
mv: cannot stat `/home/krishna/test/xy': No such file or directory
removing spaces from XML file: .xml
mv: cannot stat `z.xml': No such file or directory

Câu trả lời:


26

Sử dụng cái này với bash:

find $1 -name "* *.xml" -type f -print0 | \
  while read -d $'\0' f; do mv -v "$f" "${f// /_}"; done

findsẽ tìm kiếm các tập tin với một khoảng trắng trong tên. Tên tệp sẽ được in bằng nullbyte ( -print0) dưới dạng dấu phân cách để đối phó với tên tệp đặc biệt. Sau đó, phần readdựng sẵn đọc tên tệp được phân định bởi nullbyte và cuối cùng mvthay thế khoảng trắng bằng dấu gạch dưới.

EDIT: Nếu bạn cũng muốn xóa các khoảng trắng trong các thư mục, nó phức tạp hơn một chút. Các thư mục được đổi tên và sau đó không thể truy cập được bằng tên findtìm thấy. Thử đi:

find -name "* *" -print0 | sort -rz | \
  while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done

Việc sort -rzđảo ngược thứ tự tệp, sao cho các tệp sâu nhất trong một thư mục là lần đầu tiên di chuyển và chính thư mục đó sẽ là thư mục cuối cùng. Vì vậy, không bao giờ có thư mục được đổi tên trước khi tất cả các tệp và thư mục được đổi tên bên trong nó. Các mvlệnh trong vòng lặp là một chút thay đổi quá. Trong tên đích, chúng tôi chỉ xóa các khoảng trắng trong tên cơ sở của tệp, nếu không nó sẽ không thể truy cập được.


Tôi đang cố gắng thay thế khoảng trắng bằng dấu gạch dưới trong tất cả thư mục nhưng nó đang báo lỗi vì sau khi thay đổi tên, thư mục đó không thể truy cập được.
krishna

@krishna Tôi đã thêm một chỉnh sửa vào câu trả lời của tôi.
hỗn loạn

1
@chaos wow, chỉ chạy hai hệ thống này trên hai hệ thống và nó hoạt động như một cơ duyên, một vài tệp và thư mục không đi qua nhưng nó chỉ là một vài
thứ

Trên macOS, chúng ta cần chỉ định thư mục trong lệnh find trước tùy chọn -name find . -name "* *" -print0 | sort -rz | \ while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done
Laszlo Pinter

16
  1. Sử dụng rename

    find . -type f -name "* *.xml" -exec rename "s/\s/_/g" {} \;

    Hoặc với $1

    find "$1" -type f -name "* *.xml" -exec rename "s/\s/_/g" {} \;
  2. Sử dụng mv

    find . -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;

    Hoặc với $1

    find "$1" -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;

Tôi không biết tại sao nhưng lệnh đã cho của bạn không hiệu quả với tôi. Nó không hiển thị bất kỳ lỗi và đầu ra.
krishna

@krishna đã sửa, xin lỗi
AB

1
Đổi tên làm việc cho tôi. Nắm tay!
Brian Piercy

1

Đây là một phương pháp tôi tìm thấy trong khi đối mặt với cùng một vấn đề:

for f in *; do mv "$f" `echo $f | tr ' ' '_'`; done

Tôi đã viết một tập tin bash để tự động cập nhật chứng chỉ ssl của mình.


1

Sử dụng rename:

rename 's/\s/_/g' ./*.xml

Không cần find:)


1
thêm dấu g vào regex và nó hoạt động hoàn hảo. 's / \ s / _ / g'
jbrahy

Mẹo hay, cảm ơn :)
Jan Werkhoven
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.