Dapatkan jalur direktori file dari jalur file

400

Di Bash, jika VAR="/home/me/mydir/file.c", bagaimana saya dapatkan "/home/me/mydir"?

Talespin_Kit
sumber

Jawaban:

649

dirnamedan basenameapakah alat yang Anda cari untuk mengekstraksi komponen jalur:

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

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

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

$ basename "${VAR}"
file.c

Itu bukan perintah Bash internal tetapi itu adalah bagian dari standar POSIX (lihat dirname, basename) dan karenanya harus tersedia pada sebagian besar sistem yang akan menjalankan Bash.

paxdiablo
sumber
4
Mengapa menggunakan tanda kurung di sekitar nama variabel, dan bukan "$ VAR" misalnya?
user658182
1
stackoverflow.com/questions/8748831/… menjawab pertanyaan di atas.
user658182
1
@ user658182 Dalam contoh khusus ini, ini dilakukan karena kebiasaan, bukan keharusan.
Abandoned Cart
95
$ export VAR=/home/me/mydir/file.c
$ export DIR=${VAR%/*}
$ echo "${DIR}"
/home/me/mydir

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

Untuk menghindari ketergantungan dengan basenamedandirname

Emmanuel Devaux
sumber
3
Karena keduanya adalah bagian dari POSIX, ketergantungan seharusnya tidak menjadi masalah.
orkoden
1
orkoden, kamu benar. Tujuan dari jawaban saya adalah untuk menunjukkan bahwa tidak ada kewajiban untuk melakukan dua proses tambahan. bash cukup mandiri untuk use case.
Emmanuel Devaux
2
Saya menggunakan metode Emmanuel karena saya ingin memberikan file atau nama folder, dan kemudian menghitung jalur folder. Menggunakan regex ini melakukan hal yang benar, sedangkan fungsi dirname mengembalikan folder induk ketika saya memasukkan folder.
AnneTheAgile
8
Namun, jika tidak ada info jalur dalam $ VAR, $ {VAR% / *} / test menghasilkan nilai tak terduga sama dengan $ VAR / test sedangkan $ (dirname $ VAR) akan menghasilkan nilai ./test yang lebih mudah diprediksi dan sesuai. Ini adalah masalah besar karena yang pertama akan mencoba untuk memperlakukan nama file sebagai direktori sedangkan yang kedua akan baik-baik saja.
davemyron
19

Pada catatan terkait, jika Anda hanya memiliki nama file atau jalur relatif, dirnamedengan sendirinya tidak akan membantu. Bagi saya, jawabannya akhirnya readlink.

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

Anda kemudian dapat menggabungkan keduanya untuk mendapatkan hanya direktori.

echo $(dirname $(readlink -f "$fname")) # output: /home/me/work
jerblack
sumber
1
jika lebih dari satu komponen jalur tidak ada, Anda harus menggunakan readlink -m "$fname"untuk
mengkanonikkan
7

Jika Anda peduli file target menjadi tautan simbolis, pertama Anda dapat memeriksanya dan mendapatkan file aslinya. Klausa if di bawah ini dapat membantu Anda.

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

Saya sedang bermain dengan ini dan datang dengan alternatif.

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

$ DIR=`echo $VAR |xargs dirname`

$ echo $DIR
/home/me/mydir

Bagian yang saya suka adalah mudah untuk memperpanjang cadangan pohon:

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

$ echo $DIR
/home
Eurospoofer
sumber
1

Berikut ini adalah skrip yang saya gunakan untuk pemangkasan rekursif. Ganti $ 1 dengan direktori yang Anda inginkan, tentu saja.

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
kmchen
sumber
0

Pertama, saya telah mengganti /dengan ruang kosong ( ). Lalu, saya menghapus semua karakter sebelum ada ruang kosong ( ). Pada akhirnya, saya menghapus karakter pertama yaitu spasi kosong ( ).

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

$ echo $VAR | tr '/' ' ' | sed 's/^.* / /' | cut -c2-
file.c
Alper
sumber
0
HERE=$(cd $(dirname $BASH_SOURCE) && pwd)

di mana Anda mendapatkan path lengkap dengan new_path = $(dirname ${BASH_SOURCE[0]}). Anda mengubah direktori saat ini dengan cd new_path dan kemudian menjalankan pwduntuk mendapatkan path lengkap ke direktori saat ini.

aerijman
sumber