Làm cách nào tôi có thể vệ sinh hoặc thoát khỏi các đường dẫn tuyệt đối được trả về bởi realpath hoặc readlink?


9

realpathreadlinktrả về các đường dẫn tuyệt đối:

+akiva@X230:~$ realpath ZannaIsAwesome
/home/akiva/ZannaIsAwesome

Một con đường như thế rất dễ đối phó. Tuy nhiên, một cái gì đó như thế này sẽ có một số vấn đề:

nhập mô tả hình ảnh ở đây

Ví dụ:

nhập mô tả hình ảnh ở đây

Vì vậy, một cái tên như thế này cần được vệ sinh để có thể đưa nó vào các lệnh khác. Một usecase có thể là một cái gì đó như thế này:

+a@X230:~/\e[92mM@r|< $hu+'|'|_e|\|\|0rth [`-_-"]$ bacon=$(realpath pullingATerdon)
+a@X230:~$ vim $bacon 

Không cần phải nói, vim $baconsẽ không làm việc như mong đợi.

Tôi có thể làm gì để vệ sinh đường dẫn tuyệt đối đó để nó hoạt động với các lệnh khác?


3
Luôn trích dẫn các biến của bạn:vim "$bacon"
Steeldo

@steel ấn Tại sao vậy?
Akiva

3
Bởi vì nếu không, bạn sẽ gặp phải những tình huống như thế này :)
terdon

Câu trả lời:


12

Làm thế nào để làm điều này một cách chính xác

Trước hết, luôn luôn trích dẫn các biến của bạn . Những gì bạn đang cố gắng làm tốt nếu bạn trích dẫn đúng:

$ pwd
/home/terdon/foo/\e[92mM@r|< +'|'|_e|\|\|0rth [`-_-"]
$ ls
pullingATerdon

Tôi đã giữ tên tệp lạ mà bạn đã chọn ( mặc dù tôi không biết tại sao bạn chọn nó ) vì mục đích nhất quán.

Bây giờ, hãy gán đường dẫn của pullingATerdonmột biến và sau đó thử mở tệp:

$ bacon="$(realpath pullingATerdon)"
$ echo "$bacon"
/home/terdon/foo/\e[92mM@r|< +'|'|_e|\|\|0rth [`-_-"]/pullingATerdon
$ ls $bacon
ls: cannot access '+'\''|'\''|_e|\|\|0rth': No such file or directory
ls: cannot access '[`-_-"]/pullingATerdon': No such file or directory
'/home/terdon/foo/\e[92mM@r|<':

Điều đó thất bại, như mong đợi. Nhưng, nếu bây giờ chúng tôi trích dẫn chính xác:

$ ls -l "$bacon"
-rw-r--r-- 1 terdon terdon 0 Mar 14 23:15 '/home/terdon/foo/\e[92mM@r|< +'\''|'\''|_e|\|\|0rth [`-_-"]/pullingATerdon'

Nó hoạt động như mong đợi. Và vâng, bạn cũng có thể mở đường dẫn trong trình chỉnh sửa (thích hợp): emacs "$bacon"sẽ hoạt động tốt. OK, sẽ vimvà bất cứ điều gì khác. Sự lựa chọn của bạn về biên tập viên, mặc dù không may, không liên quan.


Tại sao bạn thất bại

Một cách nhanh chóng để theo dõi những gì thực sự xảy ra trong trường hợp của bạn là sử dụng set -x(tắt nó một lần nữa set +x), điều này khiến shell in mỗi lệnh mà nó sẽ chạy trước khi chạy nó. bật thông báo gỡ lỗi của shell với set -x:

$ set -x
$ /bin/ls $bacon 
+ ls '/home/terdon/foo/\e[92mM@r|<' '+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'
ls: cannot access '+'\''|'\''|_e|\|\|0rth': No such file or directory
ls: cannot access '[`-_-"]/pullingATerdon': No such file or directory
'/home/terdon/foo/\e[92mM@r|<':

Đó là chương trình chúng ta biết rằng lsđã chạy với ba đối số riêng biệt: '/home/terdon/foo/\e[92mM@r|<', '+'\''|'\''|_e|\|\|0rth''[`-_-"]/pullingATerdon'. Điều này xảy ra bởi vì shell thực hiện phân tách từ và mở rộng toàn cầu trên các chuỗi không được trích dẫn. Trong trường hợp này, vấn đề là phân tách từ, vì shell nhìn thấy các khoảng trắng trong đường dẫn và đọc từng chuỗi được phân tách bằng dấu cách là một đối số riêng biệt.

Các mkdirví dụ là hơi khác nhau nhưng điều đó vì bạn đang hiển thị chúng tôi được thông báo lỗi từ thứ hai gọi của lệnh. Tôi đoán bạn đã thử nó một lần, và sau đó chạy nó lần thứ hai để có được đầu ra cho câu hỏi của bạn. Lần đầu tiên bạn chạy nó, nó sẽ trông như thế này:

$ mkdir $(realpath pullingATerdon)
++ realpath pullingATerdon
+ mkdir '/home/terdon/foo/\e[92mM@r|<' '+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'
mkdir: cannot create directory ‘[`-_-"]/pullingATerdon’: No such file or directory

Một lần nữa, điều đó sẽ cố gắng tạo ba thư mục, không phải một, vì chia tách từ. Đầu tiên, nó tạo (thành công) thư mục /home/terdon/foo/\e[92mM@r|<:

$ ls -l /home/terdon/foo/
total 8
drwxr-xr-x 2 terdon terdon 4096 Mar 15 00:20 '\e[92mM@r|<'
drwxr-xr-x 3 terdon terdon 4096 Mar 15 00:20 '\e[92mM@r|< +'\''|'\''|_e|\|\|0rth [`-_-"]'

Sau đó, nó cũng thành công, tạo ra một thư mục được gọi +'|'|_e|\|\|0rthtrong thư mục hiện tại của bạn:

$ ls -l
total 4
drwxr-xr-x 2 terdon terdon 4096 Mar 15 00:37 '+'\''|'\''|_e|\|\|0rth'
-rw-r--r-- 1 terdon terdon    0 Mar 15 00:36  pullingATerdon

Và sau đó, nó đã cố gắng tạo thư mục [`-_-"]/pullingATerdon. Điều này không thành công bởi vì mkdirtheo mặc định, không tạo thư mục con (có thể, nếu bạn chạy nó với -p):

$ mkdir baz/bar
mkdir: cannot create directory baz/bar’: No such file or directory

Vì chuỗi không được trích dẫn của bạn chứa a /, mkdirđược coi là một đường dẫn gồm hai thư mục, đã cố gắng tìm thư mục trên cùng và không thành công.

Đó là lý do tại sao nó thất bại, nhưng những gì đã xảy ra thì phức tạp hơn. Chuỗi bạn sử dụng thực sự là một glob vỏ, đặc biệt là một loạt glob , mà phù hợp với tất cả các file trong thư mục hiện có tên là một trong những nhân vật 5 `, -, _hoặc ". Vì bạn không có các tệp như vậy trong thư mục hiện tại của mình, nên toàn cầu không khớp với bất cứ thứ gì và, như là hành vi mặc định trong bash, sẽ tự trả về:

$ echo "[\`-_-\"]/pullingATerdon"  ## some escaping is needed here
+ echo '[`-_-"]/pullingATerdon'    ## but it echoes the right thing
[`-_-"]/pullingATerdon             ## and matches nothing, so returns itself.

Để làm rõ, đây là những gì sẽ xảy ra nếu bạn đưa ra một quả cầu phù hợp với một cái gì đó:

$ echo [p]*   ## any filename starting with a p
pullingATerdon
$ echo "[p]*" ## the string "[p]*"
[p]*

Không trích dẫn [p*]được mở rộng vào danh sách các tên tệp phù hợp (chỉ một, trong trường hợp này) và đó là những gì được chuyển đến echo. Một lý do khác tại sao bạn nên trích dẫn tất cả mọi thứ.

Cuối cùng, lỗi thực tế bạn hiển thị là từ lần thứ hai bạn chạy lệnh và nó bị lỗi ở bước đầu tiên, khi cố gắng tạo /home/terdon/foo/\e[92mM@r|<, vì lệnh gọi trước đó đã tạo thư mục đó.


Tổng quát hơn, bất cứ khi nào bạn thấy mình làm việc với các tên tệp tùy ý, luôn luôn sử dụng các khối vỏ. Những thứ như thế này:

for file in *; do command "$file"; done

Điều đó sẽ làm việc cho bất kỳ tên tập tin. Không có vấn đề gì xảy ra để chứa. Trong ví dụ của chúng tôi ở trên, bạn có thể đã thực hiện:

emacs /home/terdon/*92mM*/pullingATerdon

Bất kỳ quả cầu nào xác định tệp mục tiêu duy nhất sẽ làm. Bằng cách đó, bạn không cần phải lo lắng về các ký tự đặc biệt và chỉ có thể để vỏ xử lý chúng.


Một số tài liệu tham khảo hữu ích:

  1. Làm cách nào tôi có thể tìm và xử lý một cách an toàn tên tệp chứa dòng mới, dấu cách hoặc cả hai? : Một trong những Câu hỏi thường gặp trên Wiki của Grey Cat xuất sắc.

  2. Ý nghĩa bảo mật của việc quên trích dẫn một biến trong shell bash / POSIX : cùng một bài tôi đã tham chiếu ở đầu câu trả lời này. Một lời giải thích tuyệt vời và rất chi tiết về tất cả những điều có thể sai nếu bạn không trích dẫn chính xác các biến shell của mình.

  3. Tại sao kịch bản shell của tôi bị sặc trên khoảng trắng hoặc các ký tự đặc biệt khác? : mọi thứ bạn từng muốn biết về việc xử lý tên tệp tùy ý trong trình bao.

  4. Khi nào cần trích dẫn kép? : Tìm hiểu thêm về dấu ngoặc kép và biến và cụ thể, một vài trường hợp bạn không cần trích dẫn chúng

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.