Làm thế nào tôi có thể chỉ nhận được tên thư mục làm việc hiện tại trong một tập lệnh bash, hoặc thậm chí tốt hơn, chỉ là một lệnh đầu cuối.
pwd
đưa ra đường dẫn đầy đủ của thư mục làm việc hiện tại, ví dụ /opt/local/bin
nhưng tôi chỉ muốnbin
Làm thế nào tôi có thể chỉ nhận được tên thư mục làm việc hiện tại trong một tập lệnh bash, hoặc thậm chí tốt hơn, chỉ là một lệnh đầu cuối.
pwd
đưa ra đường dẫn đầy đủ của thư mục làm việc hiện tại, ví dụ /opt/local/bin
nhưng tôi chỉ muốnbin
Câu trả lời:
Không cần tên cơ sở, và đặc biệt là không cần một mạng con chạy pwd (có thêm một hoạt động ngã ba, và đắt tiền ); Shell có thể thực hiện điều này trong nội bộ bằng cách sử dụng mở rộng tham số :
result=${PWD##*/} # to assign to a variable
printf '%s\n' "${PWD##*/}" # to print to stdout
# ...more robust than echo for unusual names
# (consider a directory named -e or -n)
printf '%q\n' "${PWD##*/}" # to print to stdout, quoted for use as shell input
# ...useful to make hidden characters readable.
Lưu ý rằng nếu bạn đang áp dụng kỹ thuật này trong các trường hợp khác (không phải PWD
, nhưng một số biến khác có tên thư mục), bạn có thể cần phải cắt bất kỳ dấu gạch chéo nào. Dưới đây sử dụng hỗ trợ extglob của bash để hoạt động ngay cả với nhiều dấu gạch chéo:
dirname=/path/to/somewhere//
shopt -s extglob # enable +(...) glob syntax
result=${dirname%%+(/)} # trim however many trailing slashes exist
result=${result##*/} # remove everything before the last / that still remains
printf '%s\n' "$result"
Ngoài ra, không có extglob
:
dirname="/path/to/somewhere//"
result="${dirname%"${dirname##*[!/]}"}" # extglob-free multi-trailing-/ trim
result="${result##*/}" # remove everything before the last /
$PWD
là tên của biến bash tích hợp; tất cả các tên biến tích hợp đều có trong tất cả các chữ hoa (để phân biệt chúng với các biến cục bộ, chúng phải luôn có ít nhất một ký tự chữ thường). result=${PWD#*/}
không không đánh giá để /full/path/to/directory
; thay vào đó, nó chỉ tước phần tử đầu tiên, làm cho nó path/to/directory
; sử dụng hai #
ký tự làm cho mô hình khớp với nhau, tham gia càng nhiều ký tự càng tốt. Đọc trang mở rộng tham số, được liên kết trong câu trả lời, để biết thêm.
pwd
không phải lúc nào cũng giống với giá trị của $PWD
, do các biến chứng phát sinh từ cd
ing thông qua các liên kết tượng trưng, cho dù bash có -o physical
tùy chọn được đặt hay không, v.v. Điều này được sử dụng để đặc biệt khó chịu khi xử lý các thư mục được tự động hóa, trong đó việc ghi lại đường dẫn vật lý thay vì đường dẫn logic sẽ tạo ra một đường dẫn, nếu được sử dụng, sẽ cho phép thiết bị tự động gỡ bỏ thư mục đang sử dụng.
sh
và csh
và nếu bạn muốn phím backspace để làm việc bạn phải đọc toàn bộ stty
trang người đàn ông, và chúng tôi thích nó!"
Sử dụng basename
chương trình. Đối với trường hợp của bạn:
% basename "$PWD"
bin
basename
chương trình sao? Điều gì là sai với câu trả lời này ngoài việc thiếu dấu ngoặc kép?
basename
thực sự là một chương trình bên ngoài mà làm điều đúng, nhưng chạy bất kỳ chương trình bên ngoài cho một bash điều có thể làm out-of-the-box chỉ sử dụng được xây dựng trong chức năng là ngớ ngẩn, phải gánh chịu tác động hiệu quả ( fork()
, execve()
, wait()
, vv) cho không có lý do.
basename
ở đây không áp dụng dirname
, bởi vì dirname
có chức năng ${PWD##*/}
không - chẳng hạn như chuyển đổi một chuỗi không có dấu gạch chéo .
. Do đó, trong khi sử dụng dirname
như một công cụ bên ngoài có chi phí hoạt động, nó cũng có chức năng giúp bù đắp tương tự.
function
Từ khóa không tương thích POSIX mà không thêm bất kỳ giá trị nào qua cú pháp được tiêu chuẩn hóa và việc thiếu dấu ngoặc kép sẽ tạo ra lỗi trong tên thư mục có khoảng trắng. wdexec() { "./$(basename "$PWD")"; }
có thể là một lựa chọn tốt hơn
basename
là ít "hiệu quả". Nhưng nó có thể hiệu quả hơn về năng suất của nhà phát triển vì nó dễ nhớ so với cú pháp bash xấu xí. Vì vậy, nếu bạn nhớ nó, đi cho nó. Nếu không, basename
hoạt động là tốt. Đã có ai từng phải cải thiện "hiệu suất" của tập lệnh bash và làm cho nó hiệu quả hơn chưa?
$ echo "${PWD##*/}"
Hay nói, là một tài tài của, qua, qua, qua một tài khác, qua giữ, qua một tài khác
echo "${PWD##*/}"
.
name=${PWD##*/}
sẽ đúng và name=$(echo "${PWD##*/}")
sẽ sai (theo nghĩa không cần thiết là không hiệu quả).
Bạn có thể sử dụng kết hợp pwd và basename. Ví dụ
#!/bin/bash
CURRENT=`pwd`
BASENAME=`basename "$CURRENT"`
echo "$BASENAME"
exit;
Tôi thích câu trả lời được chọn (Charles Duffy), nhưng hãy cẩn thận nếu bạn đang ở trong một thư mục liên kết tượng trưng và bạn muốn tên của thư mục tiêu. Thật không may, tôi không nghĩ rằng nó có thể được thực hiện trong một biểu thức mở rộng tham số duy nhất, có lẽ tôi đã nhầm. Điều này sẽ làm việc:
target_PWD=$(readlink -f .)
echo ${target_PWD##*/}
Để thấy điều này, một thử nghiệm:
cd foo
ln -s . bar
echo ${PWD##*/}
báo cáo "thanh"
Để hiển thị các thư mục hàng đầu của một đường dẫn (không phát sinh rẽ nhánh của / usr / bin / dirname):
echo ${target_PWD%/*}
Điều này sẽ ví dụ biến đổi foo / bar / baz -> foo / bar
readlink -f
là một phần mở rộng GNU và do đó không có sẵn trên BSD (bao gồm cả OS X).
echo "$PWD" | sed 's!.*/!!'
Nếu bạn đang sử dụng vỏ Bourne hoặc ${PWD##*/}
không có sẵn.
${PWD##*/}
là POSIX sh - mọi hiện đại / bin / sh (bao gồm dash, tro, v.v.) đều hỗ trợ nó; để đạt được Bourne thực tế trên một hộp gần đây, bạn cần phải sử dụng hệ thống Solaris hơi cũ. Ngoài ra - echo "$PWD"
; để lại dấu ngoặc kép dẫn đến lỗi (nếu tên thư mục có khoảng trắng, ký tự đại diện, v.v.).
Đáng ngạc nhiên, không ai đề cập đến sự thay thế này chỉ sử dụng các lệnh bash tích hợp:
i="$IFS";IFS='/';set -f;p=($PWD);set +f;IFS="$i";echo "${p[-1]}"
Là một phần thưởng bổ sung, bạn có thể dễ dàng có được tên của thư mục mẹ với:
[ "${#p[@]}" -gt 1 ] && echo "${p[-2]}"
Chúng sẽ hoạt động trên Bash 4.3-alpha hoặc mới hơn.
Sử dụng:
basename "$PWD"
HOẶC LÀ
IFS=/
var=($PWD)
echo ${var[-1]}
Biến Dấu tách tên tệp nội bộ (IFS) trở lại khoảng trắng.
IFS=
Có một không gian sau IFS.
basename $(pwd)
hoặc là
echo "$(basename $(pwd))"
pwd
chuỗi được phân tách và mở rộng toàn cầu trước khi được chuyển đến basename
.
basename "$(pwd)"
- mặc dù điều đó rất kém hiệu quả so với chỉ basename "$PWD"
, bản thân nó không hiệu quả so với việc sử dụng mở rộng tham số thay vì gọi basename
cả.
Đối với những người tìm thấy ngoài kia như tôi:
find $PWD -maxdepth 0 -printf "%f\n"
$PWD
để "$PWD"
xử lý chính xác tên thư mục bất thường.
tôi thường sử dụng điều này trong các kịch bản sh
SCRIPTSRC=`readlink -f "$0" || echo "$0"`
RUN_PATH=`dirname "${SCRIPTSRC}" || echo .`
echo "Running from ${RUN_PATH}"
...
cd ${RUN_PATH}/subfolder
bạn có thể sử dụng điều này để tự động hóa mọi thứ ...
Dưới grep với regex cũng đang hoạt động,
>pwd | grep -o "\w*-*$"
Chỉ dùng:
pwd | xargs basename
hoặc là
basename "`pwd`"
xargs
thức này không hiệu quả và có lỗi khi tên thư mục chứa dòng mới hoặc ký tự trích dẫn và công thức thứ hai gọi pwd
lệnh trong một lớp con, thay vì truy xuất cùng một kết quả thông qua việc mở rộng biến tích hợp.
Nếu bạn muốn chỉ xem thư mục hiện tại trong vùng nhắc bash, bạn có thể chỉnh sửa .bashrc
tệp trong ~
. Thay đổi \w
để \W
trong dòng:
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
Chạy source ~/.bashrc
và nó sẽ chỉ hiển thị tên thư mục trong vùng nhắc.
Tham chiếu: /superuser/60555/show-only-civerse-directory-name-not-full-path-on-bash-prompt
Tôi rất thích sử dụng gbasename
, đó là một phần của GNU coreutils.
basename
ở đó. Nó thường chỉ được gọi gbasename
trên MacOS và các nền tảng khác có tên cơ sở không phải là GNU.
Các lệnh sau sẽ dẫn đến việc in thư mục làm việc hiện tại của bạn trong tập lệnh bash.
pushd .
CURRENT_DIR="`cd $1; pwd`"
popd
echo $CURRENT_DIR
$1
sẽ chứa thư mục làm việc hiện tại. (2) Việc phục vụ pushd
và popd
không có mục đích ở đây vì mọi thứ bên trong backticks đều được thực hiện trong một lớp con - vì vậy nó không thể ảnh hưởng đến thư mục của shell cha. (3) Sử dụng "$(cd "$1"; pwd)"
sẽ dễ đọc và linh hoạt hơn đối với các tên thư mục có khoảng trắng.