Dapatkan nama direktori saat ini (tanpa path lengkap) dalam skrip Bash


Jawaban:


1116

Tidak perlu basename, dan terutama tidak perlu untuk menjalankan pwd subkulit (yang menambahkan operasi garpu tambahan, dan mahal ); shell dapat melakukan ini secara internal menggunakan ekspansi parameter :

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.

Perhatikan bahwa jika Anda menerapkan teknik ini dalam keadaan lain (tidak PWD, tetapi beberapa variabel lain yang memegang nama direktori), Anda mungkin perlu memotong garis miring apa pun. Di bawah ini menggunakan dukungan extglob bash untuk bekerja bahkan dengan beberapa garis miring:

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"

Atau, tanpa extglob:

dirname="/path/to/somewhere//"
result="${dirname%"${dirname##*[!/]}"}" # extglob-free multi-trailing-/ trim
result="${result##*/}"                  # remove everything before the last /

31
Apa perbedaan antara $ {PWD ## * /} dan $ PWD?
Mr_Chimp

24
@ Mr_Chimp yang pertama adalah operasi ekspansi parameter yang memotong sisa direktori untuk hanya menyediakan nama dasar. Saya memiliki tautan dalam jawaban saya untuk dokumentasi ekspansi parameter; jangan ragu untuk mengikuti itu jika Anda memiliki pertanyaan.
Charles Duffy

24
@stefgosselin $PWDadalah nama variabel bash bawaan ; semua nama variabel bawaan ada dalam huruf kapital semua (untuk membedakannya dari variabel lokal, yang harus selalu memiliki setidaknya satu karakter huruf kecil). result=${PWD#*/}tidak tidak mengevaluasi /full/path/to/directory; alih-alih, itu hanya menghapus elemen pertama, membuatnya path/to/directory; menggunakan dua #karakter membuat pola cocok serakah, serasi karakter sebanyak mungkin. Baca halaman ekspansi parameter, ditautkan dalam jawaban, untuk lebih lanjut.
Charles Duffy

5
Perhatikan bahwa output dari pwdtidak selalu sama dengan nilai $PWD, karena komplikasi yang timbul dari cdtautan simbolik, apakah bash memiliki -o physicalopsi yang disetel, dan sebagainya. Ini digunakan untuk menjadi sangat tidak enak di sekitar penanganan direktori automounted, di mana merekam jalur fisik bukannya yang logis akan menghasilkan jalur yang, jika digunakan, akan memungkinkan automounter untuk secara spontan menurunkan direktori yang digunakan.
Alex North-Keys

3
Bagus! Seseorang harus menulis buku untuk orang-orang tua dari Kalimantan seperti saya. Mungkin ada satu di luar sana? Itu bisa memiliki admin sys crotchity tua mengatakan hal-hal seperti, "kembali pada hari saya, kami hanya shdan cshdan jika Anda ingin kunci backspace bekerja Anda harus membaca sttyhalaman manual keseluruhan , dan kami menyukainya!"
Red Cricket

335

Gunakan basenameprogramnya. Untuk kasus Anda:

% basename "$PWD"
bin

20
Bukankah ini tujuan dari basenameprogram ini? Apa yang salah dengan jawaban ini selain melewatkan tanda kutip?
Nacht - Reinstate Monica

11
@Nacht basenamememang program eksternal yang melakukan hal yang benar, tetapi menjalankan setiap program eksternal untuk hal pesta dapat melakukan out-of-the-box dengan hanya menggunakan built-in fungsi konyol, menimbulkan dampak kinerja ( fork(), execve(), wait(), dll) untuk tak ada alasan.
Charles Duffy

3
... sebagai tambahan, keberatan saya untuk di basenamesini tidak berlaku dirname, karena dirnamememiliki fungsi yang ${PWD##*/}tidak - mengubah string tanpa garis miring ., misalnya. Jadi, sementara menggunakan dirnamesebagai alat eksternal memiliki overhead kinerja, itu juga memiliki fungsi yang membantu untuk mengkompensasi yang sama.
Charles Duffy

4
@LouisMaddox, sedikit kibitzing: functionKata kuncinya adalah POSIX-tidak cocok tanpa menambahkan nilai apa pun atas sintaks standar, dan kurangnya tanda kutip akan membuat bug dalam nama direktori dengan spasi. wdexec() { "./$(basename "$PWD")"; }mungkin menjadi alternatif yang lebih disukai.
Charles Duffy

28
Tentu menggunakan basenamekurang "efisien". Tapi itu mungkin lebih efisien dalam hal produktivitas pengembang karena mudah diingat dibandingkan dengan sintaksis jelek. Jadi, jika Anda mengingatnya, lakukanlah. Kalau tidak, basenameberfungsi juga. Adakah yang pernah harus meningkatkan "kinerja" skrip bash dan membuatnya lebih efisien?
usr

139
$ echo "${PWD##*/}"

​​​​​


2
@ jocap ... kecuali bahwa penggunaan gema di sana, tanpa mengutip argumen, salah . Jika nama direktori memiliki banyak spasi, atau karakter tab, itu akan diciutkan menjadi satu spasi; jika memiliki karakter wildcard, itu akan diperluas. Penggunaan yang benar akan echo "${PWD##*/}".
Charles Duffy

9
@ jocap ... juga, saya tidak yakin bahwa "gema" sebenarnya adalah bagian sah dari jawabannya. Pertanyaannya adalah bagaimana mendapatkan jawabannya, bukan bagaimana mencetak jawabannya; jika tujuannya adalah untuk menetapkannya ke variabel, misalnya, name=${PWD##*/}akan benar, dan name=$(echo "${PWD##*/}")akan salah (dalam arti tidak perlu-inefisiensi).
Charles Duffy

24

Anda dapat menggunakan kombinasi pwd dan basename. Misalnya

#!/bin/bash

CURRENT=`pwd`
BASENAME=`basename "$CURRENT"`

echo "$BASENAME"

exit;

18
Tolong jangan. Backtick membuat subkulit (dengan demikian, operasi fork) - dan dalam hal ini, Anda menggunakannya dua kali ! [Sebagai tambahan, meskipun berdalih gaya - nama variabel harus huruf kecil kecuali Anda mengekspornya ke lingkungan atau itu adalah kasus khusus, khusus].
Charles Duffy

11
dan sebagai backtics quibble gaya kedua harus diganti dengan $ (). masih bercabang tetapi lebih mudah dibaca dan dengan lebih sedikit bantuan dibutuhkan.
Jeremy Wall

1
Berdasarkan konvensi, variabel lingkungan (PATH, EDITOR, SHELL, ...) dan variabel shell internal (BASH_VERSION, RANDOM, ...) sepenuhnya dikapitalisasi. Semua nama variabel lainnya harus huruf kecil. Karena nama variabel peka terhadap huruf besar-kecil, konvensi ini menghindari variabel lingkungan dan internal yang sengaja ditimpa.
Rany Albeg Wein

2
Tergantung pada konvensi. Orang bisa berpendapat bahwa semua variabel shell adalah variabel lingkungan (tergantung pada shell), dan dengan demikian semua variabel shell harus dalam huruf kapital semua. Orang lain dapat berdebat berdasarkan ruang lingkup - variabel global semuanya terbatas, sedangkan variabel lokal lebih kecil, dan ini semua adalah global. Namun yang lain mungkin berpendapat bahwa membuat variabel huruf besar semua menambah lapisan kontras dengan perintah skrip shell, yang juga semua huruf kecil tapi bermakna kata-kata bermakna. Saya mungkin atau mungkin tidak / setuju / dengan salah satu argumen itu, tetapi saya telah melihat ketiganya digunakan. :)
dannysauer

17

Bagaimana dengan grep:

pwd | grep -o '[^/]*$'

tidak akan merekomendasikan karena tampaknya mendapatkan beberapa informasi warna sedangkan pwd | xargs basenametidak .. mungkin tidak begitu penting tetapi jawaban lainnya lebih sederhana dan lebih konsisten di seluruh lingkungan
davidhq

8

Saya suka jawaban yang dipilih (Charles Duffy), tetapi hati-hati jika Anda berada di direktori yang disinkronkan dan Anda ingin nama direktori target. Sayangnya saya tidak berpikir itu bisa dilakukan dalam ekspresi ekspansi parameter tunggal, mungkin saya salah. Ini seharusnya bekerja:

target_PWD=$(readlink -f .)
echo ${target_PWD##*/}

Untuk melihat ini, percobaan:

cd foo
ln -s . bar
echo ${PWD##*/}

melaporkan "bilah"

DIRNAME

Untuk menampilkan direktori terkemuka dari sebuah path (tanpa mengeluarkan fork-exec dari / usr / bin / dirname):

echo ${target_PWD%/*}

Ini misalnya akan mengubah foo / bar / baz -> foo / bar


5
Sayangnya, readlink -fini adalah ekstensi GNU, dan karenanya tidak tersedia pada BSD (termasuk OS X).
Xiong Chiamiov

8
echo "$PWD" | sed 's!.*/!!'

Jika Anda menggunakan shell Bourne atau ${PWD##*/}tidak tersedia.


4
FYI, ${PWD##*/}adalah POSIX sh - setiap modern / bin / sh (termasuk tanda hubung, abu, dll) mendukungnya; untuk menekan Bourne yang sebenarnya pada kotak baru-baru ini, Anda harus menggunakan sistem Solaris yang agak tua. Di luar itu - echo "$PWD"; meninggalkan tanda kutip menyebabkan bug (jika nama direktori memiliki spasi, karakter wildcard, dll).
Charles Duffy

1
Ya, saya menggunakan sistem Solaris yang oldish. Saya telah memperbarui perintah untuk menggunakan kutipan.
anomal

7

Utas ini hebat! Ini satu lagi rasa:

pwd | awk -F / '{print $NF}'

5

Anehnya, tidak ada yang menyebutkan alternatif ini yang hanya menggunakan perintah bash bawaan:

i="$IFS";IFS='/';set -f;p=($PWD);set +f;IFS="$i";echo "${p[-1]}"

Sebagai bonus tambahan, Anda dapat dengan mudah mendapatkan nama direktori induk dengan:

[ "${#p[@]}" -gt 1 ] && echo "${p[-2]}"

Ini akan bekerja pada Bash 4.3-alpha atau lebih baru.


secara mengejutkan? hanya bercanda, tetapi yang lain jauh lebih pendek dan lebih mudah diingat
codewandler

Ini cukup lucu = P Belum pernah mendengar tentang $ IFS (pemisah bidang internal) sebelum ini. pesta saya terlalu tua, tetapi dapat mengujinya di sini: jdoodle.com/test-bash-shell-script-online
Stan Kurdziel

5

Menggunakan:

basename "$PWD"

ATAU

IFS=/ 
var=($PWD)
echo ${var[-1]} 

Ubah Internal Filename Separator (IFS) kembali ke ruang kosong.

IFS= 

Ada satu ruang setelah IFS.


4
basename $(pwd)

atau

echo "$(basename $(pwd))"

2
Membutuhkan lebih banyak tanda kutip untuk menjadi benar - seperti itu, output dari pwdstring-split dan glob-diperluas sebelum diteruskan ke basename.
Charles Duffy

Jadi, basename "$(pwd)"- meskipun itu sangat tidak efisien dibandingkan dengan adil basename "$PWD", yang dengan sendirinya tidak efisien dibandingkan dengan menggunakan ekspansi parameter alih-alih memanggil basenamesama sekali.
Charles Duffy

4

Untuk menemukan joki di luar sana seperti saya:

find $PWD -maxdepth 0 -printf "%f\n"

Ubah $PWDuntuk "$PWD"untuk secara benar menangani nama direktori yang tidak biasa.
Charles Duffy

3

Saya biasanya menggunakan ini dalam skrip sh

SCRIPTSRC=`readlink -f "$0" || echo "$0"`
RUN_PATH=`dirname "${SCRIPTSRC}" || echo .`
echo "Running from ${RUN_PATH}"
...
cd ${RUN_PATH}/subfolder

Anda dapat menggunakan ini untuk mengotomatiskan hal-hal ...


readlink: illegal option -- f usage: readlink [-n] [file ...]

2

Grep bawah dengan regex juga berfungsi,

>pwd | grep -o "\w*-*$"

3
Tidak berfungsi jika nama direktori berisi karakter "-".
daniula

1

Cukup gunakan:

pwd | xargs basename

atau

basename "`pwd`"

2
Ini dalam semua hal versi yang lebih buruk dari jawaban yang sebelumnya diberikan oleh Arkady ( stackoverflow.com/a/1371267/14122 ): xargsFormultion tidak efisien dan bermasalah ketika nama direktori berisi baris baru atau karakter kutipan, dan formulasi kedua memanggil pwdperintah dalam subkulit, alih-alih mengambil hasil yang sama melalui ekspansi variabel bawaan.
Charles Duffy

@CharlesDuffy Namun, apakah itu jawaban yang valid dan praktis untuk pertanyaan itu.
bachph


0

Anda dapat menggunakan utilitas basename yang menghapus awalan yang diakhiri dengan / dan akhiran (jika ada dalam string) dari string, dan mencetak hasilnya pada output standar.

$basename <path-of-directory>

0

Saya sangat suka menggunakan gbasename, yang merupakan bagian dari GNU coreutils.


FYI, itu tidak datang dengan distribusi Ubuntu saya.
Katastic Voyage

@KatasticVoyage, ada di Ubuntu, hanya dipanggil di basenamesana. Ini biasanya dipanggil gbasenamepada MacOS dan platform lain yang jika tidak dikirimkan dengan nama pengguna non-GNU.
Charles Duffy

-1

Perintah berikut ini akan menghasilkan pencetakan direktori kerja Anda saat ini dalam skrip bash.

pushd .
CURRENT_DIR="`cd $1; pwd`"
popd
echo $CURRENT_DIR

2
(1) Saya tidak yakin di mana kami memastikan bahwa daftar argumen sedemikian rupa sehingga $1akan berisi direktori kerja saat ini. (2) The pushddanpopd tidak ada gunanya di sini karena apa pun di dalam backticks dilakukan dalam subkulit - sehingga tidak dapat memengaruhi direktori induk shell untuk memulainya. (3) Menggunakan "$(cd "$1"; pwd)"akan lebih mudah dibaca dan tahan terhadap nama direktori dengan spasi.
Charles Duffy
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.