bash: làm thế nào để bạn trả lại phần mở rộng tập tin?


7

Tôi muốn viết một tập lệnh để chỉ trả về phần mở rộng của tên tệp đầu vào. Ví dụ, textfile.txt nên trả lại txt.

Tôi mới sử dụng Linux và bash, và tôi đang cố gắng học cách viết các tập lệnh cơ bản. Cảm ơn!



2
Phần mở rộng của linux-4.2.3.tar.xztệp mà bạn có thể tải xuống từ kernel.org là gì? Phần mở rộng của /bin/bashtập tin chắc chắn có sẵn trong hệ thống của bạn là gì? Bạn thấy đấy, khái niệm "mở rộng tập tin" khá xa lạ trong Linux. Phần sau dấu chấm mang rất ít ý nghĩa đối với hệ thống - nó đúng hơn là một gợi ý cho người dùng về những gì anh ta có thể mong đợi từ tệp đó. Và gợi ý đó có thể nói dối hoặc sai.
Mirek Długosz

Câu trả lời:


25

Shell, ví dụ bash, có nhiều tính năng thao tác chuỗi . Một trong số chúng cho phép bạn loại bỏ mọi thứ theo một mẫu nhất định:

${VAR##GLOB}

Cú pháp trên loại bỏ tất cả mọi thứ từ biến $VARcho đến trận đấu đầu tiên của toàn cầu GLOB. Vì vậy, để in phần mở rộng của tệp mà không có tên của nó, bạn có thể làm:

$ file="file.txt"
$ echo ${file##*.}
txt

Lưu ý rằng điều này cũng có thể xử lý nhiều hơn một "phần mở rộng":

$ file="file.new.txt"
$ echo ${file##*.}
txt

Nếu bạn không muốn điều đó, hãy sử dụng một cái #thay thế, cái này sẽ loại bỏ trận đấu ngắn nhất thay vì dài nhất:

$ echo ${file#*.}
new.txt

Bây giờ, để chạy cái này trên tất cả các tệp trong một thư mục, bạn có thể làm:

$ ls 
file.avi  file.pdf  file.png  file.txt
$ for file in *; do echo "$file : ${file##*.}"; done
file.avi : avi
file.pdf : pdf
file.png : png
file.txt : txt

Và, để hoàn thiện, bạn cũng có thể lấy tên tệp mà không cần phần mở rộng bằng cách sử dụng ${file%.*}:

$ for file in *; do echo "$file : ${file##*.} : ${file%.*}"; done
file.avi : avi : file
file.pdf : pdf : file
file.png : png : file
file.txt : txt : file

cái này không hoạt động cho những thứ như foo / .git / bar / baz Tôi đoán bạn có thể làm echo test.txt | awk -F '/' '{in $ NF}' | awk -F '.' '{in $ NF}'
Paul M

@PaulM Ý bạn là gì? Đó là một tệp không có phần mở rộng, bạn sẽ mong đợi gì từ đó?
terdon

tiếng vang "/foo/var/.git/foo/bar.bz" | awk -F '/' '{in $ NF}' | awk -F '.' '{in $ NF}' == >> bz
Paul M

@PaulM file="/foo/var/.git/foo/bar.bz"; echo "${file##*.}": bz. Tôi không thấy một vấn đề.
terdon

4

Với việc mở rộng tham số :

$ x="textfile.txt"
$ echo ${x##*.}
txt

Các ${parameter##word}mô hình loại bỏ các tiền tố lớn nhất mà các trận đấu word(tất cả mọi thứ ngoại trừ các tập tin kết thúc).


4

Một tập lệnh bash rất đơn giản có thể làm những gì bạn muốn sẽ như sau:

#!/usr/bin/env bash

echo "$1" | awk -F '.' '{print $NF}'

Kịch bản được gọi là script.sh test.txt, và những gì nó làm là

  • nó in $1ra thiết bị xuất chuẩn. $1là tham số đầu tiên được đưa ra cho tập lệnh, trong trường hợp này test.txt.

  • đầu ra xuất chuẩn của echođược chuyển sang stdin để awktách chuỗi ( test.txt) .và sau đó in phần tử cuối cùng của phần tách ( txttrong trường hợp này).

Chỉ cần một nhận xét nhỏ, điều này có thể được thực hiện với một lớp lót vì đây là một nhiệm vụ khá đơn giản:

echo test.txt | awk -F '.' '{print $NF}'

1
Bạn cần thêm dấu ngoặc kép $1hoặc bạn có nguy cơ phá vỡ tên tệp có chứa khoảng trắng, v.v.
AP

cái này không hoạt động cho những thứ như foo / .git / bar / baz Tôi đoán bạn có thể làm echo test.txt | awk -F '/' '{in $ NF}' | awk -F '.' '{in $ NF}'
Paul M

3
#!/bin/bash

my_file=`basename "$1"` # get full file name as a script  parameter and strip the path
my_extension="${my_file##*.}"
my_file="${my_file%.*}" # will return base file name before the extension

echo "$my_file"
echo "$my_extension"

Chạy:

./script.sh index.html

Đầu ra:

index
html

Thông tin thêm: Mở rộng tham số Shell | gnu.org


3

Để làm như vậy, có một số lưu ý cần tính đến:

  • Các foo.d/bartập tin không có phần mở rộng, nó không phải là một footập tin với một .d/barphần mở rộng.
  • bạn cũng có thể muốn xem xét rằng .bashrckhông có phần mở rộng
  • Các tập tin thư mục đặc biệt ...có lẽ nên được xử lý đặc biệt và được coi là không có bất kỳ phần mở rộng nào.
  • phần mở rộng để làm file.tar.gzgì? gzhay tar.gz? Thế còn holiday.picture.jpghay bash-4.4?
  • Bạn nên trở về để làm foo.d/gì? Trống rỗng hay d?

Ở đây, tôi sẽ làm:

#! /bin/sh -
for file do
  case ${file##*/} in
    (?*.*) ext=${file##*.};;
    (*) ext=;;
  esac
  printf '%s\n' "$ext"
done

Xử lý câu trả lời tuyệt vời cũng hãy cẩn thận thông thường và mã hữu ích đặc biệt là một chức năng.
ajaaskel

0

Tôi sẽ đưa vào một số tùy chọn khác trong trường hợp bạn đã sedcài đặt hoặc Perl:

#!/bin/bash
ext=$(<<<"$1" sed -n 's/^[^.]*\.//p')
printf "Extension: $ext\n"
ext=$(<<<"$1" perl -ne 's/^.*?\.//&&print')
printf "Extension: $ext\n"
exit 0
  • s/^[^.]*\.//ptrong seds/^.*?\.//&&printtrong perl: cố gắng thay thế chuỗi ký tự ngắn nhất không được .theo sau bởi một .ký tự ở đầu chuỗi; nếu thay thế có thể được thực hiện, in kết quả của sự thay thế;
% bash script.sh file.bin
Extension: bin
Extension: bin

0

Hãy cẩn thận. Trong Unix / Linux (và MacOS), "phần mở rộng tên tệp" chỉ là thông tin (nếu nhiều). Bạn hoàn toàn có thể có một tập lệnh Perl được gọi photo.gifhoặc tệp GIF có tên poem.txt. Hoặc thậm chí một tập tin được gọi là some.txt.png.


Nó giống như thông tin trong MS Windows, chỉ là trong đó chương trình shell mặc định đưa ra các giả định mạnh mẽ hơn về việc mở rộng - ghép nối nội dung và nên có sự không khớp giữa cách đặt tên và nội dung, toàn bộ mọi thứ thường chỉ bắt đầu hét lên, người nghèo Điều.
nperson325681
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.