Dapatkan dirname / nama file terakhir dalam argumen jalur file di Bash


228

Saya mencoba menulis hook pasca-komitmen untuk SVN, yang di-host di server pengembangan kami. Tujuan saya adalah mencoba untuk secara otomatis checkout salinan dari proyek yang dikomit ke direktori di mana ia di-host di server. Namun saya harus dapat membaca hanya direktori terakhir dalam string direktori yang diteruskan ke skrip untuk checkout ke sub-direktori yang sama di mana proyek kami di-host.

Sebagai contoh jika saya membuat komitmen SVN untuk proyek "contoh", skrip saya mendapat "/ usr / local / svn / repos / example" sebagai argumen pertama. Saya perlu mendapatkan "contoh" dari ujung string dan kemudian menyatukannya dengan string lain sehingga saya dapat checkout ke "/ server / root / example" dan melihat perubahan langsung.

Jawaban:


344

basename tidak menghapus direktori awalan jalur:

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

2
basename pasti yang saya cari. Bagaimana bisa mendapatkan nama dasar argumen disimpan ke dalam variabel? MisalnyaSUBDIR="/path/to/whatever/$(basename $1)"
— TJ L

5
@ tj111: kedengarannya seperti tidak ada $1, atau $1kosong
— sth

Sayangnya, jika Anda membungkus perintah, nama bas bukan ide yang baik. hanya sesuatu yang perlu diingat
— dtc

98

Pendekatan berikut dapat digunakan untuk mendapatkan lintasan apa pun dari lintasan:

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

Keluaran:

c
b
a

1
tidak bekerja dengan jalur yang memiliki spasi ... Anda dapat mengatasinya dengan tanda kutip ... yang entah bagaimana berfungsiecho "$(basename "$(dirname "$pathname")")"
— Ray Foss

75

Bash bisa mendapatkan bagian terakhir dari jalur tanpa harus memanggil eksternal basename:

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

2
Di Mac saya, menggunakan notasi substring lebih dari urutan besarnya lebih cepat daripada dirname / nama dasar untuk kasus di mana Anda melakukan sesuatu yang sepele untuk masing-masing dari beberapa ribu file.
— George

1
d=/home/me/somefolder;subdir="/$d/${1##*/}"Saya akhirnya dengan sesuatu seperti //home/me/somefolder//$ d sebenarnya berasal dari loop for d in $(find $SOMEFOLDER -maxdepth 1 -type d);Menggunakan subdir=$(basename $d)karya seperti yang diharapkan.
— Buttle Butkus

1
@ButtleButkus: Anda harus menggunakan whilealih-alih formengulangi output dari find( find -print0 | xargs -0lebih baik) atau menggunakan globbing: for d in $SOMEFOLDER/*/(garis miring terakhir berfungsi seperti -type d- Anda dapat menggunakan **di Bash 4 untuk rekursi jika Anda shopt -s globstar, tetapi pesan "Argument list too long" adalah bisa jadi). Perhatikan bahwa ${1}bagian dari perintah mewakili argumen pertama dari skrip atau fungsi. Anda mungkin perlu menggunakan ${d##*/}atau beberapa spesifikasi variabel atau argumen atau memastikan bahwa suatu argumen sedang diajukan$1
— Dijeda sampai pemberitahuan lebih lanjut.

2
@DennisWilliamson Terima kasih banyak untuk berbagi . Untuk pembaca masa depan yang mulai bertanya - tanya mengapa itu tidak berfungsi atau saya satu-satunya yang bodoh di sini 😂. Di atas jawabannya anggap $1mengandung the path from which last component is to be taken out. Saya melewatkan bagian itu. target_path='/home/user/dir1/dir2/dir3/'; target_path="${target_path%/}"; last_component=${target_path##*/}; echo $last_componentKasing penggunaan saya: - Bekerja 😉
— Vinay Vissh

2
Lihat di sini untuk penjelasan tentang bagaimana dan mengapa ${1##*/} berfungsi: unix.stackexchange.com/a/171786/15070
— Matthew
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.