Nhận tên thư mục / tên tệp cuối cùng trong một đối số đường dẫn tệp trong Bash


228

Tôi đang cố gắng viết một hook post-commit cho SVN, được lưu trữ trên máy chủ phát triển của chúng tôi. Mục tiêu của tôi là cố gắng tự động kiểm tra một bản sao của dự án đã cam kết vào thư mục nơi nó được lưu trữ trên máy chủ. Tuy nhiên, tôi cần chỉ có thể đọc thư mục cuối cùng trong chuỗi thư mục được truyền cho tập lệnh để kiểm tra cùng thư mục con nơi các dự án của chúng tôi được lưu trữ.

Ví dụ: nếu tôi thực hiện một cam kết SVN cho "ví dụ" của dự án, tập lệnh của tôi lấy "/ usr / local / svn / repos / example" làm đối số đầu tiên. Tôi cần lấy "ví dụ" ra khỏi cuối chuỗi và sau đó nối chuỗi đó với một chuỗi khác để tôi có thể kiểm tra "/ server / root / example" và xem các thay đổi trực tiếp ngay lập tức.

Câu trả lời:


344

basename không loại bỏ tiền tố thư mục của một đường dẫn:

$ basename /usr/local/svn/repos/example
example
$ echo "/server/root/$(basename /usr/local/svn/repos/example)"
/server/root/example

2
tên cơ bản chắc chắn là những gì tôi đang tìm kiếm. Làm thế nào có thể lấy tên cơ sở của một đối số được lưu trữ trong một biến? Ví dụ:SUBDIR="/path/to/whatever/$(basename $1)"
TJ L

5
@ tj111: âm thanh như không $1, hoặc $1trống rỗng
sth

Thật không may, nếu bạn bọc các lệnh, tên cơ sở không phải là một ý tưởng tốt. chỉ cần một cái gì đó để ghi nhớ
dtc

98

Cách tiếp cận sau đây có thể được sử dụng để nhận bất kỳ đường dẫn nào của tên đường dẫn:

some_path=a/b/c
echo $(basename $some_path)
echo $(basename $(dirname $some_path))
echo $(basename $(dirname $(dirname $some_path)))

Đầu ra:

c
b
a

1
không hoạt động với các đường dẫn có khoảng trắng ... bạn có thể khắc phục điều đó bằng dấu ngoặc kép ... bằng cách nào đó hoạt độngecho "$(basename "$(dirname "$pathname")")"
Ray Foss

75

Bash có thể có được phần cuối của một con đường mà không cần phải gọi bên ngoài basename:

subdir="/path/to/whatever/${1##*/}"

2
Trên máy Mac của tôi, sử dụng ký hiệu chuỗi con nhanh hơn nhiều so với thứ tự độ lớn so với dirname / tên cơ sở cho trường hợp bạn đang làm một cái gì đó tầm thường với mỗi một vài nghìn tệp.
George

1
d=/home/me/somefolder;subdir="/$d/${1##*/}"Tôi đã kết thúc với một cái gì đó như //home/me/somefolder//$ d thực sự đến từ một vòng lặp for d in $(find $SOMEFOLDER -maxdepth 1 -type d);Sử dụng subdir=$(basename $d)các công việc như mong đợi.
Butussy Butkus

1
@BriptButkus: Bạn nên sử dụng whilethay vì forlặp đi lặp lại đầu ra của find( find -print0 | xargs -0là tốt hơn) hoặc sử dụng globalbing: for d in $SOMEFOLDER/*/(dấu gạch chéo cuối cùng hoạt động như -type d- bạn có thể sử dụng **trong Bash 4 để đệ quy nếu bạn shopt -s globstar, nhưng thông báo "Danh sách đối số quá dài" là khả thi). Lưu ý rằng ${1}phần của lệnh đại diện cho đối số đầu tiên của tập lệnh hoặc hàm. Bạn có thể cần phải sử dụng ${d##*/}hoặc một số đặc điểm kỹ thuật biến hoặc đối số khác hoặc đảm bảo rằng một đối số đang được truyền vào$1
Tạm dừng cho đến khi có thông báo mới.

2
@DennisWilliamson Cảm ơn rất nhiều vì đã chia sẻ . Đối với bất kỳ độc giả tương lai nào bắt đầu tự hỏi tại sao nó không hoạt động hoặc tôi là người ngu ngốc duy nhất ở đây . Trên câu trả lời giả định $1có chứa the path from which last component is to be taken out. Tôi đã bỏ lỡ phần đó. Trường hợp sử dụng của tôi: target_path='/home/user/dir1/dir2/dir3/'; target_path="${target_path%/}"; last_component=${target_path##*/}; echo $last_component- Công trình
Vinay Vissh

2
Xem ở đây để được giải thích về cách thứclý do ${1##*/} hoạt động: unix.stackexchange.com/a/171786/15070
Matthew
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.