Làm thế nào để chỉ lấy tên tệp bằng sed


17

Làm thế nào tôi chỉ có thể nhận được tên tệp bằng cách sử dụng sed? Tôi có cái này

out_file=$(echo $in_file|sed "s/\(.*\.\).*/\1mp4/g")

Nhưng tôi cũng nhận được con đường /root/video.mp4, và tôi chỉ muốn video.mp4.

Câu trả lời:


26

basenametừ lõi GNU có thể giúp bạn thực hiện công việc này:

$ basename /root/video.mp4
video.mp4

Nếu bạn đã biết phần mở rộng của tệp, bạn có thể gọi basenamebằng cú pháp basename NAME [SUFFIX]để xóa tệp:

$ basename /root/video.mp4 .mp4
video

Hoặc một tùy chọn khác sẽ cắt mọi thứ sau dấu chấm cuối bằng cách sử dụng sed:

$ basename /root/video.old.mp4 | sed 's/\.[^.]*$//'
video.old

3
Sử dụng sed 's/\.[^.]*$//'như bạn có, sẽ thất bại cho (ẩn) .filename...thư mục
Peter.O

9

Giải pháp đơn giản nhất là xóa mọi thứ cho đến khi xuất hiện lần cuối /:

echo /root/video.mp4 | sed 's/.*\///'


5

Sử dụng bất kỳ cách nào sau đây:

out_file="${in_file##*/}"

out_file="$(basename $in_file)"

out_file="$(echo $in_file | sed 's=.*/==')"

out_file="$(echo $in_file | awk -F"/" '{ print $NF }')"

ps. Bạn nhận được cùng một chuỗi bởi vì trong câu lệnh của bạn \(.*\.\)khớp với chuỗi từ đầu cho đến khi dấu chấm ( /root/video.) và sau đó bạn thêm thủ công .mp4giống như trong chuỗi gốc của bạn. Bạn nên sử dụng s=.*\([^/]*\)=\1=thay thế.

Cập nhật: (Cái đầu tiên đã được sửa bây giờ)

Để có được tên tệp duy nhất mà không cần gia hạn, bạn có thể:

out_file="$(echo $in_file | sed 's=.*/==;s/\.[^.]*$/.new_ext/')"

out_file="$(echo $in_file | sed 's=\([^/]*\)\.[^./]*$=\1.new_ext=')"

out_file="$(echo $in_file | awk -F"/" '{ gsub (/\.[^/.]*$/,".new_ext",$NF);print $NF }'

Nhưng với bất kỳ phương pháp nào trong số đó, tôi nhận được tên tệp với định dạng và tôi chỉ cần lấy tên tệp và đặt định dạng mới theo cách thủ công.
Shixons

Ah, điều đó có ý nghĩa. Tôi đã cập nhật câu trả lời của mình.
vội vàng

@rush: Sẽ có trường hợp cạnh, ví dụ cho một tệp có tên my.file.tar.gz.
donothings thành công

@donothingsuccess đã có một biểu tượng dấu chấm bị thiếu cuối cùng sedawk. Đã sửa. Cảm ơn bạn.
vội vàng

4

Một trong những nguyên tắc cơ bản của việc sử dụng regex là các mẫu tự nhiên là tham lam khi chỉ định thẻ hoang dã. Mặc dù câu trả lời được đề xuất bởi @uloBasEI chắc chắn là một câu trả lời hoạt động, nó cũng yêu cầu sử dụng lệnh basename. Câu hỏi ban đầu từ @Shixons yêu cầu một giải pháp chỉ sử dụng sed.

Trước khi tiếp tục, thật hữu ích khi biết phiên bản sed nào là mục tiêu. Tôi đang giả sử BSD (như được vận chuyển với OSX).

Trước hết, mẫu được đề xuất trong câu hỏi ban đầu không hoạt động vì nó nắm bắt mọi thứ từ đầu chuỗi đầu vào cho đến và bao gồm cả dấu chấm cuối cùng. Không có neo, tìm kiếm này sẽ nuốt chửng mọi thứ từ trái sang phải. Do đó, mẫu phù hợp "/ 1" là mọi thứ lên đến và bao gồm cả dấu chấm cuối cùng. Ngay cả một tên tệp có nhiều dấu chấm sẽ bị nuốt chửng toàn bộ. Không phải là kết quả mong muốn ở tất cả.

Bước đầu tiên là thiết lập một chiến lược để xác định các mẫu. Tại đây, bạn muốn loại bỏ mọi thứ ở bên trái tên tệp (chúng ta sẽ giải quyết phần mở rộng sau):

out_file="$(echo $in_file | sed 's/^\(\/.*\/\)*.*/\1/')"

Tìm kiếm phù hợp từ đầu chuỗi. Nó khớp với mẫu "/.*" 0 hoặc nhiều lần và xóa mọi thứ sau đó. Chúng tôi in các mẫu phù hợp với "\ 1". Chúng tôi không tìm kiếm trên toàn cầu; chúng tôi đang tìm kiếm từ đầu chuỗi bằng cách chỉ định ^ neo.

Chúng tôi hiểu rõ hơn bằng cách bật tùy chọn "-E" để chúng tôi không phải thoát dấu ngoặc đơn:

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*.*/\1/')"

Vì vậy, bây giờ chúng ta có phần bên trái. Hãy thêm phần bên phải. Lưu ý rằng chúng ta cần giữ phần bên trái dưới dạng mẫu vì đó là cách chúng ta có thể chỉ định rằng phần đó xuất hiện 0 hoặc nhiều lần. Tất cả những gì chúng ta làm bây giờ là thêm một mẫu cho phần bên phải:

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)/\2/')"

Chúng tôi chỉ in ra trận đấu thứ hai, do đó loại bỏ mọi thứ trừ tên tệp. Nhưng chúng ta vẫn cần xóa phần mở rộng tên tệp.

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2/')"

"$" Ở cuối là tùy chọn.

Cuối cùng, để thêm tiện ích mở rộng mới, bạn chỉ cần sửa lại như vậy:

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2.mp4/')"

Một tối ưu hóa bổ sung là làm cho dấu gạch chéo chuyển tiếp đầu tiên tùy chọn để xử lý các đường dẫn tương đối:

out_file="$(echo $in_file | sed -E 's/^([\/]?.*\/)*(.*)\..*$/\2.mp4/')"

Tôi bắt gặp câu hỏi này bằng cách lười biếng trong khi tìm kiếm một mẫu sed để thay thế tên cơ sở . Tôi đang làm việc trên một hệ thống bị tước mà không cài đặt lệnh đó.

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.