Câu hỏi Đổi tên tệp hàng loạt bằng Bash


Làm thế nào Bash có thể đổi tên một loạt các gói để loại bỏ số phiên bản của họ? Tôi đã chơi đùa với cả hai expr và %%, không có kết quả.

Ví dụ:

Xft2-2.1.13.pkg trở thành Xft2.pkg

jasper-1.900.1.pkg trở thành jasper.pkg

xorg-libXrandr-1.2.3.pkg trở thành xorg-libXrandr.pkg


76
2018-03-02 15:20


gốc


Tôi có ý định sử dụng thường xuyên, như một kịch bản viết một lần sử dụng-rất nhiều. Bất kỳ hệ thống nào tôi sẽ sử dụng sẽ có bash trên nó, vì vậy tôi không sợ các bashism khá tiện dụng. - Jeremy L
Nhìn chung cũng thấy stackoverflow.com/questions/28725333/… - tripleee


Các câu trả lời:


Bạn có thể sử dụng tính năng mở rộng tham số của bash

for i in ./*.pkg ; do mv "$i" "${i/-[0-9.]*.pkg/.pkg}" ; done

Cần có dấu ngoặc kép cho tên tệp có dấu cách.


149
2018-03-02 15:33



Tôi thích điều này tốt nhất cho đến nay! - Jeremy L
Tôi thích nó quá, nhưng nó sử dụng các tính năng bash-cụ thể ... Tôi thường không sử dụng chúng trong lợi của sh "tiêu chuẩn". - Diego Sevilla
Đối với công cụ tương tác một dòng, tôi luôn sử dụng nó thay vì sed-fu. Nếu nó là một kịch bản, vâng, tránh bashisms. - richq
Để tránh các lỗi chạy lại, bạn có thể sử dụng cùng một mẫu trong ".pkg "một phần, tức là" cho i in * - [0-9.].pkg; làm mv $ i $ {i / - [0-9.] *. pkg / .pkg}; nhưng lỗi là vô hại đủ (di chuyển đến cùng một tập tin). - richq
Không phải là một giải pháp bash, nhưng nếu bạn đã cài đặt perl, nó cung cấp lệnh đổi tên tiện dụng để đổi tên hàng loạt, chỉ cần làm rename "s/-[0-9.]*//" *.pkg - Woofas


Nếu tất cả các tệp nằm trong cùng một thư mục, chuỗi

ls | 
sed -n 's/\(.*\)\(-[0-9.]*\.pkg\)/mv "\1\2" "\1.pkg"/p' | 
sh

sẽ làm công việc của bạn. Các quyến rũ lệnh sẽ tạo một chuỗi mv lệnh, sau đó bạn có thể đưa vào trình bao. Cách tốt nhất để chạy đường ống đầu tiên mà không có dấu vết | sh để xác minh rằng lệnh thực hiện những gì bạn muốn.

Để recurse thông qua nhiều thư mục sử dụng một cái gì đó như

find . -type f |
sed -n 's/\(.*\)\(-[0-9.]*\.pkg\)/mv "\1\2" "\1.pkg"/p' |
sh

Lưu ý rằng trong quyến rũ trình tự nhóm biểu thức chính quy là các dấu ngoặc đứng trước dấu gạch chéo ngược, \( và \), chứ không phải là dấu ngoặc đơn ( và ).


27
2018-03-02 15:54



Tha thứ cho sự ngây thơ của tôi, nhưng sẽ không thoát khỏi các dấu ngoặc đơn với các dấu gạch chéo ngược khiến chúng được coi là các ký tự theo nghĩa đen? - devios1
Trong sed chuỗi thứ tự biểu thức chính quy là (, chứ không phải là một dấu ngoặc đơn. - Diomidis Spinellis
đã không làm việc cho tôi, sẽ được vui để có được sự giúp đỡ của bạn .... Hậu tố của tập tin FROM được nối vào tập tin TO: $ find. -type d | - () >>>>> OUTPUT >>>> mv: đổi tên ./base/src/main/java/com/anysoftkeyboard/base/dictionaries thành ./base/src/main/java/com/effectedkeyboard/base/dictionaries/dictionaries : Không có tập tin hoặc thư mục - Vitali Pom
Dường như bạn thiếu dấu gạch chéo ngược trong dấu ngoặc vuông. - Diomidis Spinellis


Tôi sẽ làm một cái gì đó như thế này:

for file in *.pkg ; do
    mv $file $(echo $file | rev | cut -f2- -d- | rev).pkg
done

cho rằng tất cả tệp của bạn nằm trong thư mục hiện tại. Nếu không, cố gắng sử dụng tìm kiếm như được tư vấn ở trên bởi Javier.

CHỈNH SỬA: Ngoài ra, phiên bản này không sử dụng bất kỳ tính năng bash-cụ thể, như những người khác ở trên, dẫn bạn đến tính di động hơn.


9
2018-03-02 15:35



Họ là tất cả trong cùng một thư mục. Bạn nghĩ gì về câu trả lời của rq? - Jeremy L
Tôi không thích sử dụng các tính năng bash-cụ thể, nhưng thay vào đó là tiêu chuẩn sh hơn. - Diego Sevilla
Tôi cho rằng điều này là để đổi tên nhanh chóng, không phải để viết nền tảng thế hệ tiếp theo, Ứng dụng doanh nghiệp di động ;-) - richq
Haha, đủ công bằng ... Chỉ cần ra khỏi một người đàn ông có tính di động như tôi :) - Diego Sevilla
Điều này không tính đến ví dụ thứ ba: xorg-libXrandr (dấu gạch nối được sử dụng trong tên). - Jeremy L


sử dụng tốt hơn sed cho điều này, một cái gì đó như:

find . -type f -name "*.pkg" |
 sed -e 's/((.*)-[0-9.]*\.pkg)/\1 \2.pkg/g' |
 while read nameA nameB; do
    mv $nameA $nameB;
 done

figuring up biểu thức chính quy là trái như một bài tập (như là đối phó với tên tập tin bao gồm không gian)


3
2018-03-02 15:30



Cảm ơn: Không gian không được sử dụng trong tên. - Jeremy L


Điều này dường như làm việc giả định rằng

  • mọi thứ kết thúc bằng $ pkg
  • phiên bản của bạn luôn bắt đầu bằng "-"

loại bỏ .pkg, sau đó bỏ đi - ..

for x in $(ls); do echo $x $(echo $x | sed 's/\.pkg//g' | sed 's/-.*//g').pkg; done

1
2018-03-02 15:33



Có một số gói có dấu nối trong tên của chúng (xem ví dụ thứ ba). Điều này có ảnh hưởng đến mã của bạn không? - Jeremy L
Bạn có thể chạy nhiều biểu thức sed bằng cách sử dụng -e. Ví dụ. sed -e 's/\.pkg//g' -e 's/-.*//g'. - nojak
Không phân tích cú pháp ls đầu ra và trích dẫn các biến của bạn. Xem thêm shellcheck.net để chẩn đoán các vấn đề phổ biến và các mẫu mã trong các kịch bản lệnh shell. - tripleee


Tôi đã có nhiều *.txt tệp được đổi tên thành .sql trong cùng một thư mục. dưới đây làm việc cho tôi:

for i in \`ls *.txt | awk -F "." '{print $1}'\` ;do mv $i.txt $i.sql; done

1
2017-11-05 17:22



Bạn có thể cải thiện câu trả lời của mình bằng cách tóm tắt câu trả lời đó cho trường hợp sử dụng thực tế của OP. - dakab
Điều này có nhiều vấn đề cũng như một lỗi cú pháp rõ ràng. Xem shellcheck.net Cho một sự khởi đầu. - tripleee


Đây là một POSIX gần tương đương với câu trả lời hiện đang được chấp nhận. Điều này giao dịch chỉ Bash ${variable/substring/replacement} mở rộng tham số cho một cái có sẵn trong bất kỳ trình bao tương thích Bourne nào.

for i in ./*.pkg; do
    mv "$i" "${i%-[0-9.]*.pkg}.pkg"
done

Mở rộng tham số ${variable%pattern} tạo ra giá trị của variable với bất kỳ hậu tố nào phù hợp pattern đã xóa. (Cũng có ${variable#pattern} để xóa tiền tố.)

Tôi giữ mẫu con -[0-9.]* từ câu trả lời được chấp nhận mặc dù nó có lẽ gây hiểu lầm. Nó không phải là một biểu thức chính quy, mà là một mẫu hình cầu; do đó, nó không có nghĩa là "một dấu gạch ngang theo sau là số không hoặc nhiều số hoặc dấu chấm". Thay vào đó, nó có nghĩa là "một dấu gạch ngang, theo sau là một số hoặc một dấu chấm, tiếp theo là bất cứ điều gì". "Mọi thứ" sẽ là trận đấu ngắn nhất có thể, không phải là dài nhất. (Bash cung cấp ## và %% để cắt tỉa tiền tố hoặc hậu tố dài nhất có thể, thay vì ngắn nhất.)


1
2018-03-04 19:41





Cảm ơn bạn vì câu trả lời này. Tôi cũng có một số vấn đề. Di chuyển tệp .nzb.queued sang tệp .nzb. Nó có không gian và các tàu khác trong tên tập tin và điều này đã giải quyết được vấn đề của tôi:

find . -type f -name "*.nzb.queued" |
sed -ne "s/^\(\(.*\).nzb.queued\)$/mv -v \"\1\" \"\2.nzb\"/p" |
sh

Nó dựa trên câu trả lời của Diomidis Spinellis.

Regex tạo một nhóm cho toàn bộ tên tệp, và một nhóm cho phần trước .nzb.queued và sau đó tạo ra một lệnh di chuyển shell. Với các chuỗi được trích dẫn. Điều này cũng tránh tạo ra một vòng lặp trong kịch bản shell vì điều này đã được thực hiện bởi sed.


0
2017-10-30 08:53



Cần lưu ý rằng điều này chỉ đúng với GNU sed. Trên BSDs sed sẽ không diễn giải -n tùy chọn theo cùng một cách. - ocodo