Nhận đường dẫn thư mục tệp từ đường dẫn tệp


400

Trong Bash, nếu VAR="/home/me/mydir/file.c", làm thế nào để tôi có được "/home/me/mydir"?

Câu trả lời:


648

dirnamebasenamelà các công cụ bạn đang tìm kiếm để trích xuất các thành phần đường dẫn:

$ VAR=/home/me/mydir/file.c

$ DIR=$(dirname "${VAR}")

$ echo "${DIR}"
/home/me/mydir

$ basename "${VAR}"
file.c

Chúng không phải là các lệnh Bash bên trong mà là một phần của tiêu chuẩn POSIX (xem dirname, basename) và do đó nên có sẵn trên phần lớn các hệ thống sẽ chạy Bash.


4
Tại sao việc sử dụng dấu ngoặc quanh tên biến và không phải là "$ VAR" chẳng hạn?
dùng658182

1
stackoverflow.com/questions/8748831/ Câu trả lời cho câu hỏi trên.
dùng658182

1
@ user658182 Trong ví dụ cụ thể này, nó được thực hiện theo thói quen, không cần thiết.
Giỏ hàng bị bỏ rơi

95
$ export VAR=/home/me/mydir/file.c
$ export DIR=${VAR%/*}
$ echo "${DIR}"
/home/me/mydir

$ echo "${VAR##*/}"
file.c

Để tránh phụ thuộc với basenamedirname


3
Vì cả hai đều là một phần của POSIX, nên sự phụ thuộc không phải là vấn đề.
orkoden

1
orkoden, bạn đúng. Mục đích của câu trả lời của tôi là cho thấy không có nghĩa vụ phải thực hiện hai quy trình bổ sung. bash là đủ cho trường hợp sử dụng.
Emmanuel Devaux

2
Tôi đang sử dụng phương pháp của Emmanuel vì tôi muốn chuyển một tệp hoặc tên thư mục và sau đó tính toán đường dẫn thư mục. Sử dụng regex này thực hiện đúng, trong khi chức năng dirname trả về thư mục mẹ khi tôi nhập thư mục.
AnneTheAgile

8
Tuy nhiên, nếu không có thông tin đường dẫn trong $ VAR, $ {VAR% / *} / test tạo ra giá trị không mong muốn bằng $ VAR / test trong khi $ (dirname $ VAR) sẽ tạo ra giá trị phù hợp và dễ đoán hơn là ./test. Đây là một vấn đề lớn bởi vì cái trước sẽ cố gắng coi tên tệp là một thư mục trong khi cái sau sẽ ổn.
davemyron

19

Trên một lưu ý liên quan, nếu bạn chỉ có tên tệp hoặc đường dẫn tương đối, thì dirnamenó sẽ không giúp ích gì. Đối với tôi, câu trả lời cuối cùng đã được readlink.

fname='txtfile'    
echo $(dirname "$fname")                # output: .
echo $(readlink -f "$fname")            # output: /home/me/work/txtfile

Sau đó, bạn có thể kết hợp cả hai để có được thư mục.

echo $(dirname $(readlink -f "$fname")) # output: /home/me/work

1
nếu không tồn tại nhiều thành phần đường dẫn, bạn nên sử dụng readlink -m "$fname"để chuẩn hóa tên được đặt theo cách đệ quy
EDkan

7

Nếu bạn quan tâm các tệp mục tiêu là liên kết tượng trưng, ​​trước tiên bạn có thể kiểm tra nó và lấy tệp gốc. Mệnh đề if dưới đây có thể giúp bạn.

if [ -h $file ]
then
 base=$(dirname $(readlink $file))
else
 base=$(dirname $file)
fi

5

Tôi đã chơi với điều này và đưa ra một giải pháp thay thế.

$ VAR=/home/me/mydir/file.c

$ DIR=`echo $VAR |xargs dirname`

$ echo $DIR
/home/me/mydir

Phần tôi thích là dễ dàng mở rộng sao lưu cây:

$ DIR=`echo $VAR |xargs dirname |xargs dirname |xargs dirname`

$ echo $DIR
/home

1

Đây là một kịch bản tôi đã sử dụng để cắt đệ quy. Thay thế $ 1 với thư mục bạn muốn, tất nhiên.

BASEDIR="$1"
IFS=$'\n'
cd $BASEDIR
 for f in $(find . -type f -name ' *')
 do 
    DIR=$(dirname "$f")
    DIR=${DIR:1}
    cd $BASEDIR$DIR
    rename 's/^ *//' *
 done

0

Đầu tiên, tôi đã thay thế /bằng khoảng trống ( ). Sau đó, tôi xóa tất cả các ký tự trước bất kỳ khoảng trống nào ( ). Cuối cùng, tôi loại bỏ ký tự đầu tiên là khoảng trống ( ).

$ VAR="/home/me/mydir/file.c"

$ echo $VAR | tr '/' ' ' | sed 's/^.* / /' | cut -c2-
file.c

0
HERE=$(cd $(dirname $BASH_SOURCE) && pwd)

nơi bạn có được đường dẫn đầy đủ với new_path = $(dirname ${BASH_SOURCE[0]}). Bạn thay đổi thư mục hiện tại với cd new_path và sau đó chạy pwdđể có được đường dẫn đầy đủ đến thư mục hiện tại.

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.