Sử dụng tên tệp kết thúc bằng một dấu chấm


7

Tại sao Unix cho phép các tệp có một khoảng thời gian ở cuối tên? Có bất kỳ sử dụng cho điều này?

Ví dụ:

filename.

Tôi đang hỏi bởi vì tôi có một chức năng đơn giản lặp lại phần mở rộng của một tập tin.

ext() {
  echo ${1##*.}
}

Nhưng biết nó sẽ không in gì nếu tên tệp kết thúc bằng a ., tôi tự hỏi liệu nó có đáng tin cậy hơn để viết không:

ext() {
  extension=${1##*.}
  if [ -z "$extension" ]; then
    echo "$1"
  else
    echo "$extension"
  fi
}

Rõ ràng điều này phụ thuộc vào những gì bạn đang cố gắng thực hiện, nhưng nếu .phần cuối của tên tệp không được phép, tôi sẽ không tự hỏi bất cứ điều gì ở nơi đầu tiên.


Bạn đã có câu trả lời từ Michael. Thêm hai ghi chú viết mã của bạn. Đặt tên, example.tar.gzbạn sẽ loại bỏ tất cả các hậu tố bắt đầu từ dấu chấm đầu tiên, sẽ không có phần mở rộng duy nhất cần thiết để gọi đúng chương trình để xử lý. Và nếu tên tệp của bạn không có "phần mở rộng" được phân tách bằng dấu chấm, thì chức năng của bạn sẽ in toàn bộ tên đã nhập, vì vậy bạn cần kiểm tra thêm để trả về một chuỗi trống trong trường hợp đó.
Janis

Nhận xét của tôi là giải quyết các tên thường có nhiều hơn một dấu chấm hoặc không có dấu chấm nào cả. (Nếu tất cả các tệp của bạn được đảm bảo luôn chỉ có một dấu chấm - đó là một hạn chế không phổ biến nếu bạn hiểu câu trả lời của Michael - và nếu bạn cũng không xem xét các tệp chấm, tức là tệp bắt đầu bằng dấu chấm, bạn có thể ổn. Nếu không, bạn nên suy nghĩ lại về vấn đề này.)
Janis

1
Nếu tôi muốn đặt tên cho các tập tin của mình với các câu đầy đủ, tôi sẽ mong đợi nhiều tên kết thúc ..
Paulo Ebermann

Câu trả lời:


28

Tên tệp Unix chỉ là chuỗi byte và có thể chứa bất kỳ byte nào ngoại trừ /NULở bất kỳ vị trí nào. Không có khái niệm "phần mở rộng" tích hợp như trong Windows và các hệ thống tập tin của nó, và vì vậy không có lý do gì để không cho phép tên tệp kết thúc (hoặc bắt đầu) với bất kỳ ký tự nào có thể xuất hiện trong chúng nói chung - .không có gì đặc biệt hơn hơn một x.

Tại sao Unix cho phép các tệp có một khoảng thời gian ở cuối tên? "Chuỗi byte" là một định nghĩa đơn giản và không loại trừ tên khi không có lý do thúc đẩy để tính ra thứ gì đó mà không có. Làm và áp dụng một quy tắc để loại trừ một cái gì đó cụ thể là công việc nhiều hơn.

Có sử dụng cho nó? Nếu bạn muốn tạo một tập tin với tên đó, chắc chắn. Có sử dụng cho một tên tệp kết thúc bằng x? Tôi không thể nói rằng tôi thường tạo một tên tệp .ở cuối, nhưng cả hai .xrõ ràng là một phần của bộ ký tự tên tệp di động được yêu cầu phải được hỗ trợ chung và không phải là đặc biệt theo bất kỳ cách nào, vì vậy nếu tôi có sử dụng cho nó (có thể cho một mã hóa được tạo ra bằng cơ học) sau đó tôi có thể, và tôi có thể dựa vào nó hoạt động.


Đồng thời, tên tệp đặc biệt .(dấu chấm) và ..(dấu chấm), đề cập đến các thư mục hiện tại và thư mục gốc, được ủy quyền bởi POSIX và cả hai đều kết thúc bằng a .. Bất kỳ mã nào liên quan đến tên tệp nói chung đều cần phải giải quyết chúng.


3
Nitpick: "có thể chứa bất kỳ ký tự nào ngoại trừ / và NUL" chính xác hơn "có thể chứa bất kỳ byte nào ngoại trừ 0x2F và 0x00" - sự khác biệt quan trọng khi ai đó cố gắng tạo tên tệp được mã hóa trong mã hóa siêu mã hóa ASCII, có vẻ hoạt động cho đến khi bạn vượt qua 0x2F hoặc 0x00 mà không đứng một mình. (Đã nói rằng, bạn phải đi thật xa để gặp phải vấn đề này trong thực tế; không có lựa chọn thông thường nào về "mã hóa ký tự kế thừa vụng về" (Shift-JIS, Big5 và EBCDIC) có thể sử dụng 0x2F như một phần của một nhân vật đồ họa khác với /.)
zwol

1
@zwol: Tất nhiên bạn đúng về điểm byte / ký tự. Tôi đã sửa nó. POSIX thực sự bắt buộc rằng "mã hóa một byte của ký tự <slash> được yêu cầu phải giống nhau trên tất cả các vị trí và không xảy ra trong một ký tự nhiều byte" và các đường dẫn là các chuỗi kết thúc null, vì vậy trường hợp khác có thể sẽ xuất hiện Điều đó có nghĩa là, ví dụ, UTF-16 không phải là mã hóa hệ thống tệp hợp lệ trên hệ thống Unix.
Michael Homer

5

Câu hỏi thực sự là, tại sao bất kỳ hệ điều hành nào cũng có ý nghĩa trong '.' ? Không có lý do kỹ thuật để làm như vậy, đó chỉ là một tiêu chuẩn có thể giúp bạn giả sử loại tệp mà không cần kiểm tra.

Nếu bạn đổi tên tệp MP3 thành .txt và cố gắng mở tệp đó trong windows, bạn sẽ thấy ngay lý do tại sao ý tưởng đó có nhược điểm: bạn đột nhiên "không thể" mở tệp chính xác. Về mặt kỹ thuật, không có bất kỳ cân nhắc nào về tốc độ và do đó, cách tốt nhất có thể là xác định loại tệp trước khi quyết định làm gì với nó, vì các tiện ích mở rộng dễ bị xáo trộn và có thể gây ra sự cố.

Lý do linux không quan tâm đến một khoảng thời gian trong tên là cùng một lý do mà một người không sử dụng máy tính không có: không có sự khác biệt vốn có giữa một thời kỳ và bất kỳ nhân vật nào khác ngoài thực tế là một số chương trình được mã hóa để xem thời kỳ đó và đối xử với nó đặc biệt

Giả sử bạn thực sự chỉ muốn tiện ích mở rộng (đó không phải là điều mà cả hai đoạn trích của bạn làm), bạn có thể sử dụng điều này:

ext(){
    extension=
    [[ $1 =~ \. ]] && extension="${1##*.}"
    echo "$1 -> ${extension:-No extension}"
}

ext something.    # something. -> No extension
ext something.txt # something.txt -> txt
ext something     # something -> No extension
ext som.thing.mp3 # som.thing.mp3 -> mp3
ext .whatever     # .whatever -> whatever

* Lưu ý rằng cuối cùng.

Nếu bạn thực sự muốn trả lại tên tệp khi không có phần mở rộng, giống như mã của bạn, không có lý do gì để sử dụng đoạn mã thứ hai dài, kiểu SH mà bạn có. Bạn đã viết:

ext() {
  extension=${1##*.}
  if [ -z "$extension" ]; then
    echo "$1"
  else
    echo "$extension"
  fi
}

Đó thực sự chỉ là:

ext(){
 extension="${1##*.}"
 # This line is what your first snippet is doing: 
 # echo "$extension"
 # This line is what your second snippet is doing:
 [[ $extension ]] && echo "$extension" || echo "$1"
}

Đó thực sự chỉ là:

# First snippet
ext(){
 echo "${1##*.}"
}

# Second snippet
ext(){
 extension="${1##*.}"
 echo "${extension:-$1}"
}

Về cơ bản, bạn không thể chấp nhận bất cứ điều gì mà người dùng có thể nhập vào. Nếu bạn muốn xem loại tập tin thực sự là gì, hãy thử lệnh tập tin. Bởi vì phân tích tên tệp để cố gắng tìm ra loại tệp không phải là cách duy nhất để lột da con mèo đó. Bạn thậm chí có thể có một tên tệp trong linux được gọi đơn giản là: \


4
Lý do đằng sau việc sử dụng \ ở cuối hoặc $ là gì? Không cần phải có, vì chúng là các ký tự hợp lệ. Bạn đang chọn "." cụ thể như thể có bất kỳ sự khác biệt thực tế. Không có.
Nate

Đúng, nhưng mã echo ${1##*.}chỉ quan tâm đến các khoảng thời gian và nếu các khoảng thời gian ở cuối tên tệp không được phép, tôi sẽ không phải suy nghĩ về trường hợp đặc biệt của giai đoạn kết thúc tên tệp.
Jorge Bucaran

4
@JorgeBucaran Và nếu mã của bạn đang tách tên tệp và ký tự tùy ý khác, bạn sẽ gặp vấn đề tương tự nếu ở cuối; Không? Bạn chỉ đang chọn ..
Boris the Spider

@BoristheSpider Anh ấy "chọn ." vì sử dụng cái này làm dấu phân tách cho một phần mở rộng là một quy ước chung và nhiều tập lệnh được viết trên giả định này.
Barmar 11/03/2015
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.