Làm cách nào để chia biến $ 0 để tìm thư mục và đường dẫn tương đối trong bash?


10

Biến $ 0 chứa thông tin đường dẫn của tập lệnh.

  • Làm cách nào để thay đổi thông tin đường dẫn thành đường dẫn tuyệt đối? Ý tôi là làm thế nào để xử lý ~,., .. hoặc tương tự?
  • Làm thế nào tôi có thể chia thông tin đường dẫn vào thư mục và tên tệp?

Tôi có thể sử dụng python / perl cho việc này, nhưng tôi muốn sử dụng bash nếu có thể.


bạn đang cố gắng để đạt được điều gì? btw. gọi một tập lệnh với ~ / foo.sh sẽ mở rộng ~ vào thư mục chính của tôi với giá 0 đô la với phiên bản bash của tôi (GNU bash, phiên bản 4.1.5 (2) -release- (x86_64-unknown-linux-gnu))
echox

Câu trả lời:


17

Bạn không cần phải xử lý những thứ như ~, vỏ làm nó cho bạn. Đó là lý do tại sao bạn có thể chuyển ~/filenameđến bất kỳ tập lệnh hoặc chương trình nào và nó hoạt động - tất cả các chương trình đó không ~tự xử lý , trình bao của bạn chuyển đổi đối số thành /home/username/filenamevà chuyển điều đó sang chương trình thay thế:

$ echo ~/filename
/home/mrozekma/filename

Nếu bạn cần một tên tệp chính tắc (một tên không bao gồm những thứ như ..), hãy sử dụng realpath(cảm ơn Neil ):

$ realpath ~/../filename
/home/filename

Đối với việc chia đường dẫn vào tên thư mục và tên tệp, hãy sử dụng dirnamebasename:

$ dirname /foo/bar/baz
/foo/bar

$ basename /foo/bar/baz
baz

Tôi nghĩ bạn có nghĩa là realpath, không đọc. readlink sẽ không hoạt động trong tình huống phổ biến, tức là khi liên kết sử dụng một đường dẫn tương đối và bạn không ở cùng một đường dẫn như liên kết.
Neil Mayhew

@Neil realpathtốt hơn, nhưng readlinkdường như hoạt động khi tôi thử nó; Bạn có biết một ví dụ mà nó thất bại?
Michael Mrozek

1
cd /tmp; touch foo; ln -s foo bar; cd; readlink /tmp/bar. Điều này trở lại foorealpathtrả lại /tmp/foo, đó là những gì bạn muốn.
Neil Mayhew

1
@Neil, @Michael: readlink -f(lưu ý -f) gần như tương đương realpathvà nó dễ mang theo hơn: readlink -ftrong lõi GNU và cũng tồn tại trên một vài hệ thống khác; realpathđược đóng gói riêng và có thể không được cài đặt (ví dụ: chỉ có 5 gói không phổ biến phụ thuộc vào nó trong Ubuntu 10.04 hoặc Debian lenny).
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles: điểm tốt. Cảm ơn đã nhắc nhở về realpath -f.
Neil Mayhew

5

Sử dụng dirname và tên cơ sở như được đề cập bởi Michael sẽ là cách an toàn nhất để có được những gì bạn muốn.

Dù sao, nếu bạn thực sự muốn làm điều này với "bash only tools", bạn có thể sử dụng thay thế tham số:

echo `basename $PWD`        # Basename of current working directory.
echo "${PWD##*/}"           # Basename of current working directory.
echo
echo `basename $0`          # Name of script.
echo $0                     # Name of script.
echo "${0##*/}"             # Name of script.
echo
filename=test.data
echo "${filename##*.}"      # data
                            # Extension of filename.

Ví dụ này được lấy trực tiếp từ Hướng dẫn lập trình Bash nâng cao rất đáng xem.

Giải thích khá đơn giản:

$ {var # Pattern} Xóa khỏi $ var phần ngắn nhất của $ Pattern khớp với mặt trước của $ var. $ {var ## Pattern} Xóa khỏi $ var phần dài nhất của $ Pattern khớp với mặt trước của $ var.

Nhìn vào mô hình như một số regex và #hoặc ##như một loại sửa đổi tham lam / không tham lam.

Điều này có thể trở nên hữu ích nếu bạn sẽ phải thực hiện một số trích xuất phức tạp hơn của một phần đường dẫn.


5
Cẩn thận khi sử dụng ${...##...}và bạn bè hơn là dirnamebasenamehọ không làm việc trong mọi trường hợp. Ví dụ: cả hai ${0##*/}${0%/*}mở rộng giống như $0thể $0không chứa a /.
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles Tôi hiểu tại sao ${0%/*}không phải là một thay thế tốt để dirname. Tuy nhiên, có gì sai khi sử dụng ${0##*/}thay vì basename?
toxalot

@toxalot Đối với cái này, vấn đề duy nhất là khi $0một tên thư mục có dấu /. Nhưng tôi rất tiếc lời khuyên của mình, vì dirnamekhông làm gì tốt hơn.
Gilles 'SO- ngừng trở thành ác quỷ'

2

realpath là một lệnh cho bạn biết đường dẫn thực (loại bỏ .. và các liên kết tượng trưng, ​​v.v.)

Nó là tiêu chuẩn với FreeBSD. Theo cuộc thảo luận này, nó cũng có sẵn cho Linux:

http://www.unix.com/shell-programming-scripting/89294-geting-real-path.html

Cuộc thảo luận đó cũng đưa ra một giải pháp bash:

$ bash -c "cd /foo/../bar/ ; pwd"

1
Chính xác, một cái gì đó như thế này thường hoạt động: MYDIR = "$ (cd $ (dirname" $ ​​0 "); pwd)"
Kevin Cantu
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.