Là không gian không được phép trong một tên tệp?


31

Người ta nói rằng trên Unix và Linux nói chung, bạn nên tránh có khoảng trắng trong tên tệp của tệp (tệp thông thường, thư mục, liên kết, tệp thiết bị, ...).

Nhưng tôi làm điều đó mọi lúc. Đối với tên tệp có khoảng trắng bên trong,

  • Trong Nautilus, nhân vật không gian được hiển thị dưới dạng khoảng trắng.
  • Trong thiết bị đầu cuối Bash, tôi hoặc sử dụng \ để thể hiện một khoảng trắng hoặc đặt tên tệp trong một cặp dấu ngoặc kép.
  • trong một số tệp của ứng dụng (Nautilus, không chắc hệ điều hành cũng sẽ làm như vậy), tên tệp được ghi bằng khoảng trắng được thay thế bằng %20.

Là một không gian thực sự không được phép trong một tên tệp?

Làm thế nào để bạn sử dụng hoặc xử lý một khoảng trắng trong tên tệp một cách chính xác?


17
Nó được cho phép nhưng nó thực sự, thực sự gây phiền nhiễu. Không có lý do của nó. Đừng làm điều đó.
Cuộc đua nhẹ nhàng với Monica

3
Bạn cũng có thể tạo một tệp có tên -rf ~(sử dụng touch -- "-rf ~"), nhưng tôi không khuyến nghị.
Ian D. Scott

5
Bạn có thể làm điều đó, điều đó được cho phép, như tạo ra một kịch bản tự hủy có tên là "cd" nhưng bạn không nên làm điều đó. Tệp của bạn đã trông khác nhau ở 3 công cụ khác nhau, điều đó có đủ tệ không?
Falco

7
Không phải ai cũng chia sẻ ý kiến ​​rằng nó thực sự, thực sự gây phiền nhiễu. Và "không có lý do cho điều đó" rõ ràng là sai đến mức nó không cần phải bác bỏ. Tôi đã nhượng bộ và học cách xử lý các không gian đúng cách nhiều năm trước, và đối với hầu hết các phần, nó thực sự không phải là một vấn đề lớn.

2
@snailboat Spaces là một triệu chứng của vấn đề thực sự là thiếu tiêu chuẩn hóa. Hệ thống tập tin Unix cho phép tập tin "tên" vào các đốm nhị phân gần như không bị hạn chế. Các byte bất hợp pháp duy nhất là 0 và 47 ( /dấu phân cách). Sử dụng tất cả 254 byte còn lại sẽ mở ra cơ hội cho tất cả các cách sử dụng "tên" eldritch không thể nói được. Rõ ràng điều này là điên rồ, nhưng không phải ai cũng đồng ý về "lành mạnh" là gì, và các nhân vật khác nhau sẽ phá vỡ các công cụ khác nhau. Giao điểm của sự tỉnh táo của mọi người là khá nhỏ .
jw013

Câu trả lời:


48

Không gian, và thực sự mọi nhân vật ngoại trừ /và NUL, đều được phép trong tên tệp. Khuyến cáo không sử dụng khoảng trắng trong tên tệp xuất phát từ mối nguy hiểm mà chúng có thể bị hiểu sai bởi phần mềm hỗ trợ chúng kém. Có thể cho rằng, phần mềm như vậy là lỗi. Nhưng cũng có thể cho rằng, các ngôn ngữ lập trình như shell script khiến phần mềm viết quá dễ bị hỏng khi xuất hiện tên tệp có khoảng trắng trong đó và các lỗi này có xu hướng lướt qua vì các kịch bản shell thường không được các nhà phát triển của họ kiểm tra bằng cách sử dụng tên tệp có dấu cách họ

Không gian được thay thế bằng %20không thường thấy trong tên tệp. Điều đó chủ yếu được sử dụng cho các URL (web). Mặc dù sự thật là% mã hóa từ các URL đôi khi xâm nhập vào tên tệp, thường là tình cờ.


6
Đó là "Mã hóa URL" hoặc "mã hóa phần trăm" vi.wikipedia.org/wiki/URL_encoding Theo đó, tên thích hợp nhất có lẽ là "Mã hóa URI", nhưng mọi người tìm thấy url dễ nói hơn URI , vì vậy đây là một dạng phổ biến của hiểu sai. Lưu ý tập hợp các ký tự dành riêng trong URI lớn hơn so với tên tệp * nix.
goldilocks

1
@Tim Tôi không biết rằng bạn có thể chỉ định một ký tự NUL trong bất kỳ đối số dòng lệnh nào trong bash. Tôi đã thử một vài thứ như trích dẫn nó bằng Ctrl-V và một cái gì đó tương tự $(echo -e \\0)nhưng nó không hoạt động. Vấn đề là, lý do NUL không thể được sử dụng trong tên tệp là vì nó không thể được sử dụng trong chuỗi C (vì đó là bộ kết thúc chuỗi) và tất cả các API cơ bản cũng như hầu như tất cả các chuỗi được xử lý bởi các chương trình C đều sử dụng định dạng đó . Vì bashđược viết bằng C, nên đơn giản là nó không có hỗ trợ cho bất kỳ chuỗi nào có NUL trong đó. Tôi có thể sai, có thể có một số cách tối nghĩa ...
Celada

1
Sắp xếp phụ thuộc vào bối cảnh. Các hàm chuỗi thường không tính null cuối cùng (hay đúng hơn, null đầu tiên là cuối chuỗi, ngay cả khi có thứ gì đó sau chuỗi), do đó, theo nghĩa đó, nó có độ dài bằng 0 và do đó sẽ được coi là trống.
goldilocks

3
@Celada tất nhiên bạn có thể sử dụng NULvà bash, bạn cần $'\0'. Ví dụ:find . -print0 | while read -d $'\0' f; do echo "$f"; done
terdon

1
@goldilocks Mọi người có thực sự phát âm URL là 'url', đại khái là vần với 'bá tước' không?
Miles Rout

17

Không gian được phép trong tên tệp, như bạn đã quan sát.

Nếu bạn nhìn vào mục "hầu hết các hệ thống tập tin UNIX" trong biểu đồ này trong wikipedia , bạn sẽ nhận thấy:

  • Bất kỳ bộ ký tự 8 bit nào đều được phép. Chúng ta cũng có thể sử dụng ASCII 7 bit dưới cái ô này, vì nó là tập hợp con của các bộ 8 bit khác nhau và luôn được triển khai bằng cách sử dụng byte 8 bit.

  • Các ký tự bị cấm duy nhất là /và "null". "Null" đề cập đến một byte bằng 0, nhưng dù sao chúng không được phép trong dữ liệu văn bản.

Tuy nhiên , nếu bạn sử dụng shell, bạn có thể nhận ra rằng có một số ký tự sẽ tạo ra rắc rối, đáng kể nhất *, đó là toán tử toàn cầu POSIX.

Tùy thuộc vào cách bạn muốn xác định "rắc rối", bạn có thể bao gồm khoảng trắng (khoảng trắng, tab, dòng mới, v.v.) trong đó, vì điều này tạo ra nhu cầu trích dẫn "". Nhưng điều này là không thể tránh khỏi, vì không gian được cho phép, nên ...

Làm thế nào để bạn sử dụng hoặc xử lý một khoảng trắng trong tên tệp một cách chính xác?

Trong ngữ cảnh shell / dòng lệnh, bọc tên tệp trong dấu ngoặc đơn hoặc dấu ngoặc kép (nhưng lưu ý rằng chúng không giống với các vấn đề khác của WRT) hoặc thoát khỏi khoảng trắng bằng \, ví dụ:

> foo my\ file\ with\ spaces\ in\ the\ name

1
Làm thế nào để bạn xác định nhân vật NUL trong bash? Tôi muốn kiểm tra nó trong một tên tệp.
Tim

1
Bạn không thể. "Ngữ nghĩa thực thi" đề cập đến thực tế là trong C (và mọi ngôn ngữ khác mà tôi biết), các chuỗi văn bản đều bị chấm dứt. Shell được triển khai trong C. Điều lén lút nhất mà tôi có thể nghĩ đến là touch $(echo -e "foo\00bar")- -exử lý \0Nnhư một giá trị bát phân, nhưng nó vẫn bị mất ở đâu đó, vì điều đó chỉ tạo ra một tệp có tên foobar. Tất nhiên NULL không thể in được, nhưng tôi đảm bảo rằng nó đã đi từ đó vì hạn chế chuỗi C.
goldilocks

"chuỗi văn bản không được kết thúc" -> Để giải thích thêm: chuỗi luôn được lưu trữ với một byte bằng 0 ở cuối, đó là lý do tại sao nó "không được phép" trong văn bản: Nếu bạn chèn một chuỗi, bạn đã chấm dứt chuỗi một cách hiệu quả tại thời điểm đó. Ví dụ, foo[NULL]barsẽ kết thúc như foođối với hầu hết các ý định và mục đích. Thực tế không xảy ra với điều đó echo -echo thấy NULL đã được cắt bỏ ở đâu đó.
goldilocks

5
Phần lớn các ngôn ngữ lập trình không cho phép các ký tự null trong chuỗi. Nó chỉ xảy ra rằng ngôn ngữ chính không phải là C, mà Unix được xây dựng trên - và hầu hết các shell Unix cũng không cho phép các ký tự null trong chuỗi. Trong mọi trường hợp, @Tim, tất cả các giao diện Unix đều sử dụng các chuỗi kết thúc null, do đó, byte rỗng là thứ bạn không bao giờ có trong tên tệp (cộng với /đó là dấu tách thư mục và không thể được trích dẫn, vì vậy có thể nằm trong tên đường dẫn nhưng không phải trong một tên tệp).
Gilles 'SO- ngừng trở nên xấu xa'

1
... nhưng [đừng bận tâm nữa]. Dù sao, không phải là điều tôi sẽ làm quá thường xuyên. Đối với tôi, không có lý do gì để chúng có trong dữ liệu văn bản. Tôi đã sửa nó, nhưng đó là một nhận xét.
goldilocks

3

Lý do phần lớn mang tính lịch sử - CÁCH trở lại trong không gian thời gian không được phép trong tên tệp, vì vậy khoảng trắng được sử dụng làm dấu tách từ khóa / tên tệp. Các trình thông dịch shell trong tương lai phải tương thích ngược với các tập lệnh cũ, và do đó chúng ta bị mắc kẹt với vấn đề đau đầu hiện nay.

Các nhà phát triển các quy trình không cần phải đối phó với con người rất nhiều có thể làm cho mọi thứ trở nên dễ dàng hơn nhiều bằng cách bỏ hoàn toàn các không gian. Apple thực hiện điều này, nội dung của / System / Library / CoreService / chứa rất ít khoảng trắng, các chương trình có khoảng trắng được mở thay mặt cho người dùng vàWouldLookStrange IfCamelCasing. Đường dẫn unix tương tự cũng tránh không gian.

(giai thoại hơi liên quan: vào giữa những năm 90, một máy bay không người lái Windows đã nói "Đặt tên cho một điều bạn có thể làm trên máy Mac mà tôi không thể làm trên Windows" -> "Sử dụng 12 ký tự trong tên tệp." -> Im lặng. cũng có thể có trong 12 ký tự đó)


1
Tôi đã từng sử dụng động cơ Unix Unix (c. 1978). Không gian đã được cho phép sau đó. Một nhiệm vụ tôi đã có là viết một chương trình để phân tích hệ thống tệp (sử dụng đĩa trực tiếp i / o) và tìm kiếm một tệp có khoảng trắng và khoảng trống trong tên của nó.
wallyk

họ có bỏ không gian hoàn toàn không - hay tên tập tin có chứa một vài khoảng trắng?
mikeerv

2

Vì vậy, có, như đã nói nhiều lần ở nơi khác, một tên tệp có thể chứa gần như bất kỳ ký tự nào. Nhưng nó cần phải được nói rằng một tên tập tinkhông một tập tin. Nó có trọng lượng như một thuộc tính tệp trong đó bạn thường cần một tên tệp để mở tệp, nhưng tên tệp chỉ trỏ đến tệp thực tế. Nó là một liên kết, được lưu trữ trong thư mục đã ghi lại nó, cùng với số inode - gần đúng với một tập tin thực tế .

Vì vậy, bạn biết, gọi nó là bất cứ điều gì bạn muốn. Hạt nhân không quan tâm - tất cả các tham chiếu tệp mà nó sẽ xử lý sẽ xử lý các số inode thực. Tên tệp là một thứ dành cho con người - nếu bạn muốn biến nó thành một thứ điên rồ, thì đó là hệ thống tập tin của bạn. Ở đây, tôi sẽ làm một số thứ điên rồ:

Đầu tiên tôi sẽ tạo 20 tệp và đặt tên cho chúng không có gì ngoài khoảng trắng, mỗi tên tệp chứa thêm một khoảng trắng so với cuối cùng:

until [ $((i=$i+1)) -gt 20 ]
do  v=$v' ' && touch ./"$v"
done

Điều này thật buồn cười. Hãy nhìn tôi ls:

ls -d ./*
./      ./          ./              ./                  ./                 
./      ./          ./              ./                  ./                  
./      ./          ./              ./                  ./                   
./      ./          ./              ./                  ./     

Bây giờ tôi sẽ phản chiếu thư mục này:

set -- * ; mkdir ../mirror
ls -i1qdU -- "$@" |
sh -c 'while read inum na
    do  ln -T "$1" ../mirror/$inum
    shift ; done' -- "$@"
ls -d ../mirror/*

Dưới đây là ../mirror/nội dung:

../mirror/423759  ../mirror/423764  ../mirror/423769  ../mirror/423774
../mirror/423760  ../mirror/423765  ../mirror/423770  ../mirror/423775
../mirror/423761  ../mirror/423766  ../mirror/423771  ../mirror/423776
../mirror/423762  ../mirror/423767  ../mirror/423772  ../mirror/423777
../mirror/423763  ../mirror/423768  ../mirror/423773  ../mirror/423778

Ok, nhưng có lẽ bạn đang hỏi - nhưng điều đó có gì tốt? Làm thế nào bạn có thể biết đó là cái gì? Làm thế nào bạn thậm chí có thể chắc chắn rằng bạn đã liên kết số inode bên phải với tên tệp đúng?

Tốt...

echo "heyhey" >>./'    ' 
tgt=$(ls -id ./'    ')
cat ../mirror/${tgt%% .*} \
    $(ls -1td ../mirror/* | head -n1) 

ĐẦU RA

heyhey
heyhey

Xem, cả số inode có trong ../mirror/"${tgt%% .*}"và được tham chiếu bằng cách ./' 'tham chiếu đến cùng một tệp. Họ mô tả cùng một tập tin. Họ đặt tên cho nó, nhưng không có gì hơn. Thực sự không có gì bí ẩn, chỉ là một số bất tiện mà bạn có thể tự tạo ra, nhưng cuối cùng sẽ có rất ít ảnh hưởng đến hoạt động của hệ thống tập tin unix của bạn.

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.