Bagaimana cara membagi variabel $ 0 untuk menemukan direktori dan jalur relatif di bash?


10

Variabel $ 0 berisi info jalur skrip.

  • Bagaimana saya bisa mengubah info jalur ke jalur absolut? Maksud saya cara memproses ~,., .. atau serupa?
  • Bagaimana saya bisa membagi info jalur ke direktori dan nama file?

Saya bisa menggunakan python / perl untuk ini, tapi saya ingin menggunakan bash jika memungkinkan.


apa yang ingin kamu capai? btw. memanggil skrip dengan ~ / foo.sh akan diperluas ~ ke direktori home saya untuk $ 0 dengan versi bash saya (GNU bash, versi 4.1.5 (2) -release- (x86_64-unknown-linux-gnu))
echox

Jawaban:


17

Anda tidak perlu memproses hal-hal seperti ~, shell melakukannya untuk Anda. Itu sebabnya Anda bisa meneruskan ~/filenameke skrip atau program apa pun dan berhasil - semua program itu tidak menangani ~sendiri, shell Anda mengonversi argumen itu /home/username/filenamedan meneruskannya ke program:

$ echo ~/filename
/home/mrozekma/filename

Jika Anda memerlukan nama file kanonik (yang tidak termasuk hal-hal seperti ..), gunakan realpath(terima kasih Neil ):

$ realpath ~/../filename
/home/filename

Adapun untuk memecah jalur menjadi nama direktori dan nama file, gunakan dirnamedan basename:

$ dirname /foo/bar/baz
/foo/bar

$ basename /foo/bar/baz
baz

Saya pikir maksud Anda realpath, bukan readlink. readlink tidak akan berfungsi dalam situasi umum, yaitu saat tautan menggunakan jalur relatif dan Anda tidak berada di direktori yang sama dengan tautan tersebut.
Neil Mayhew

@ Neil realpathlebih baik, tetapi readlinktampaknya berfungsi ketika saya mencobanya; apakah Anda tahu contoh gagal?
Michael Mrozek

1
cd /tmp; touch foo; ln -s foo bar; cd; readlink /tmp/bar. Ini kembali foodan realpathkembali /tmp/foo, itulah yang Anda inginkan.
Neil Mayhew

1
@Neil, @Michael: readlink -f(note -f) hampir setara dengan realpath, dan lebih portabel: readlink -fdi GNU coreutils dan ada pada beberapa sistem lain juga; realpathdikemas secara terpisah dan mungkin tidak diinstal (mis. hanya 5 paket tidak umum yang bergantung padanya di Ubuntu 10.04 atau Debian lenny).
Gilles 'SANGAT berhenti menjadi jahat'

@Gilles: poin bagus. Terima kasih atas pengingat tentang realpath -f.
Neil Mayhew

5

Menggunakan dirname dan nama kecil seperti yang disebutkan oleh Michael harus menjadi cara teraman untuk mendapatkan apa yang Anda inginkan.

Pokoknya jika Anda benar-benar ingin melakukan ini dengan "alat bash saja" Anda bisa menggunakan substitusi parameter:

echo `basename $PWD`        # Basename of current working directory.
echo "${PWD##*/}"           # Basename of current working directory.
echo
echo `basename $0`          # Name of script.
echo $0                     # Name of script.
echo "${0##*/}"             # Name of script.
echo
filename=test.data
echo "${filename##*.}"      # data
                            # Extension of filename.

Contoh ini diambil langsung dari Panduan Script Bash Lanjutan yang patut dilihat.

Penjelasannya cukup sederhana:

$ {var # Pattern} Hapus dari $ var bagian terpendek dari $ Pattern yang cocok dengan ujung depan $ var. $ {var ## Pattern} Hapus dari $ var bagian terpanjang dari $ Pattern yang cocok dengan ujung depan $ var.

Lihatlah polanya seperti regex dan #atau ##sebagai semacam modifier yang serakah / tidak serakah.

Ini mungkin berguna jika Anda harus melakukan ekstraksi bagian path yang lebih rumit.


5
Waspadalah saat menggunakan ${...##...}dan berteman daripada dirnamedan basenamebahwa mereka tidak bekerja dalam semua kasus. Misalnya keduanya ${0##*/}dan ${0%/*}perluas sama seperti $0jika $0tidak mengandung a /.
Gilles 'SO- stop being evil'

@Gilles Saya mengerti mengapa ${0%/*}ini bukan alternatif yang baik dirname. Namun, apa salahnya menggunakan ${0##*/}bukan basename?
toxalot

@toxalot Untuk yang ini, satu-satunya masalah adalah kapan $0nama direktori dengan trailing /. Tetapi saya menyesali saran saya, karena dirnametidak melakukan yang lebih baik.
Gilles 'SANGAT berhenti menjadi jahat'

2

realpath adalah perintah yang memberi tahu Anda jalan yang sebenarnya (menghapus .. dan tautan simbolik dll.)

Ini standar dengan FreeBSD. Menurut diskusi ini juga tersedia untuk Linux:

http://www.unix.com/shell-programming-scripting/89294-geting-real-path.html

Diskusi itu juga menawarkan solusi bash:

$ bash -c "cd /foo/../bar/ ; pwd"

1
Tepat, sesuatu seperti ini biasanya berfungsi: MYDIR = "$ (cd $ (dirname" $ ​​0 "); pwd)"
Kevin Cantu
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.