Bagaimana saya bisa menentukan nama file skrip Bash di dalam skrip itu sendiri?
Seperti jika skrip saya ada dalam file runme.sh
, lalu bagaimana saya membuatnya untuk menampilkan pesan "Anda menjalankan runme.sh" tanpa hardcoding itu?
Bagaimana saya bisa menentukan nama file skrip Bash di dalam skrip itu sendiri?
Seperti jika skrip saya ada dalam file runme.sh
, lalu bagaimana saya membuatnya untuk menampilkan pesan "Anda menjalankan runme.sh" tanpa hardcoding itu?
Jawaban:
me=`basename "$0"`
Untuk membaca symlink 1 , yang biasanya bukan yang Anda inginkan (Anda biasanya tidak ingin membingungkan pengguna dengan cara ini), cobalah:
me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
IMO, itu akan menghasilkan output yang membingungkan. "Aku berlari foo.sh, tapi katanya aku menjalankan bar.sh !? Pasti bug!" Selain itu, salah satu tujuan memiliki symlink yang berbeda nama adalah untuk menyediakan fungsionalitas yang berbeda berdasarkan nama yang disebutnya (pikirkan gzip dan gunzip pada beberapa platform).
1 Yaitu, untuk menyelesaikan symlink sehingga ketika pengguna mengeksekusi foo.sh
yang sebenarnya merupakan symlink bar.sh
, Anda ingin menggunakan nama yang diselesaikan bar.sh
alih-alih foo.sh
.
$0
pada contoh pertama tunduk pada pemisahan kata, 3. $0
diteruskan ke nama file, readlink, dan gema dalam posisi yang memungkinkannya untuk diperlakukan sebagai saklar baris perintah . Saya menyarankan sebagai gantinya me=$(basename -- "$0")
atau jauh lebih efisien dengan mengorbankan keterbacaan me=${0##*/}
,. Untuk symlink, me=$(basename -- "$(readlink -f -- "$0")")
dengan asumsi gnu utils, jika tidak maka akan menjadi skrip yang sangat panjang yang tidak akan saya tulis di sini.
# ------------- SCRIPT ------------- # # ------------- DISEBUT ------ ------- #
#!/bin/bash
echo
echo "# arguments called with ----> ${@} "
echo "# \$1 ----------------------> $1 "
echo "# \$2 ----------------------> $2 "
echo "# path to me ---------------> ${0} "
echo "# parent path --------------> ${0%/*} "
echo "# my name ------------------> ${0##*/} "
echo
exit
# Perhatikan pada baris berikutnya, argumen pertama disebut dalam tanda kutip ganda, # dan tunggal, karena mengandung dua kata
$ / misc / shell_scripts / check_root / show_parms . sh "'halo di sana'" "'william'"
# ------------- HASIL ------------- #
# argumen dipanggil dengan ---> 'hello there' 'william' # $ 1 ----------------------> 'hello there' # $ 2 ---- ------------------> path 'william' ke saya --------------> / misc / shell_scripts / check_root / show_parms. sh # parent path -------------> / misc / shell_scripts / check_root # nama saya -----------------> show_parms.sh
# ------------- AKHIR ------------- #
show_params
, yaitu nama tanpa ekstensi opsional?
${0##*/}
. Diuji menggunakan GitBash.
Dengan bash> = 3 , karya-karya berikut:
$ ./s
0 is: ./s
BASH_SOURCE is: ./s
$ . ./s
0 is: bash
BASH_SOURCE is: ./s
$ cat s
#!/bin/bash
printf '$0 is: %s\n$BASH_SOURCE is: %s\n' "$0" "$BASH_SOURCE"
dirname $BASE_SOURCE
" untuk mendapatkan direktori tempat skrip berada.
$BASH_SOURCE
memberikan jawaban yang benar saat sumber skrip.
Namun ini termasuk path sehingga untuk mendapatkan nama file skrip saja, gunakan:
$(basename $BASH_SOURCE)
. <filename> [arguments]
, $0
akan memberikan nama penelepon shell. Yah setidaknya di OSX pasti.
Jika nama script memiliki ruang di dalamnya, cara yang lebih kuat adalah dengan menggunakan "$0"
atau "$(basename "$0")"
- atau MacOS: "$(basename \"$0\")"
. Ini mencegah nama menjadi rusak atau ditafsirkan dengan cara apa pun. Secara umum, itu adalah praktik yang baik untuk selalu menggandakan nama variabel dalam shell.
Jika Anda menginginkannya tanpa path maka Anda akan menggunakannya ${0##*/}
Untuk menjawab Chris Conway , di Linux (setidaknya) Anda akan melakukan ini:
echo $(basename $(readlink -nf $0))
readlink mencetak nilai tautan simbolik. Jika itu bukan tautan simbolis, ia mencetak nama file. -n mengatakan itu untuk tidak mencetak baris baru. -f mengatakan itu untuk mengikuti tautan sepenuhnya (jika tautan simbolis adalah tautan ke tautan lain, itu akan menyelesaikannya juga).
Saya menemukan baris ini selalu berfungsi, terlepas dari apakah file tersebut bersumber atau dijalankan sebagai skrip.
echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
Jika Anda ingin mengikuti symlink, gunakan readlink
jalur yang Anda dapatkan di atas, secara rekursif atau non-rekursif.
Alasan one-liner berfungsi dijelaskan oleh penggunaan BASH_SOURCE
variabel lingkungan dan asosiasinya FUNCNAME
.
BASH_SOURCE
Variabel array yang anggotanya adalah nama file sumber tempat nama fungsi shell yang sesuai dalam variabel array FUNCNAME didefinisikan. Fungsi shell $ {FUNCNAME [$ i]} didefinisikan dalam file $ {BASH_SOURCE [$ i]} dan dipanggil dari $ {BASH_SOURCE [$ i + 1]}.
FUNCNAME
Variabel array yang berisi nama-nama semua fungsi shell saat ini dalam tumpukan panggilan eksekusi. Elemen dengan indeks 0 adalah nama dari setiap fungsi shell yang sedang dijalankan. Elemen terbawah (yang memiliki indeks tertinggi) adalah "utama". Variabel ini hanya ada ketika fungsi shell mengeksekusi. Tugas untuk FUNCNAME tidak berpengaruh dan mengembalikan status kesalahan. Jika FUNCNAME tidak disetel, FUNCNAME akan kehilangan properti khususnya, bahkan jika kemudian disetel ulang.
Variabel ini dapat digunakan dengan BASH_LINENO dan BASH_SOURCE. Setiap elemen FUNCNAME memiliki elemen yang sesuai di BASH_LINENO dan BASH_SOURCE untuk menjelaskan tumpukan panggilan. Misalnya, $ {FUNCNAME [$ i]} dipanggil dari file $ {BASH_SOURCE [$ i + 1]} di nomor baris $ {BASH_LINENO [$ i]}. Penelepon bawaan menampilkan tumpukan panggilan saat ini menggunakan informasi ini.
[Sumber: Bash manual]
a
(anggap a
isinya echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
) dari sesi interaktif - maka itu akan memberi Anda a
jalan. Tetapi jika Anda menulis naskah b
dengan source a
di dalamnya dan menjalankannya ./b
, itu akan kembali b
jalur 's.
Jawaban ini benar untuk kasus yang mereka nyatakan tetapi masih ada masalah jika Anda menjalankan skrip dari skrip lain menggunakan kata kunci 'sumber' (sehingga berjalan di shell yang sama). Dalam hal ini, Anda mendapatkan $ 0 dari skrip panggilan. Dan dalam hal ini, saya rasa tidak mungkin untuk mendapatkan nama skrip itu sendiri.
Ini adalah kasus tepi dan tidak boleh dianggap terlalu serius. Jika Anda menjalankan skrip dari skrip lain secara langsung (tanpa 'sumber'), menggunakan $ 0 akan berfungsi.
Karena beberapa komentar bertanya tentang nama file tanpa ekstensi, berikut ini adalah contoh bagaimana melakukannya:
FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}
Nikmati!
Re: Jawaban Tanktalus (diterima) di atas, cara yang sedikit lebih bersih adalah dengan menggunakan:
me=$(readlink --canonicalize --no-newline $0)
Jika skrip Anda bersumber dari skrip bash lain, Anda dapat menggunakan:
me=$(readlink --canonicalize --no-newline $BASH_SOURCE)
Saya setuju bahwa itu akan membingungkan untuk symlink dereference jika tujuan Anda adalah untuk memberikan umpan balik kepada pengguna, tetapi ada saat-saat ketika Anda perlu mendapatkan nama kanonik ke skrip atau file lain, dan ini adalah cara terbaik, imo.
source
nama skrip d.
jika skrip shell Anda aktifkan
/home/mike/runme.sh
$ 0 adalah nama lengkap
/home/mike/runme.sh
basename $ 0 akan mendapatkan nama file dasar
runme.sh
dan Anda perlu memasukkan nama dasar ini ke dalam variabel seperti
filename=$(basename $0)
dan tambahkan teks tambahan Anda
echo "You are running $filename"
jadi skrip Anda suka
/home/mike/runme.sh
#!/bin/bash
filename=$(basename $0)
echo "You are running $filename"
this="$(dirname "$(realpath "$BASH_SOURCE")")"
Ini menyelesaikan tautan simbolik (realpath melakukan itu), menangani spasi (tanda kutip ganda melakukan ini), dan akan menemukan nama skrip saat ini bahkan ketika bersumber (./myscript) atau dipanggil oleh skrip lain ($ BASH_SOURCE menangani itu). Setelah semua itu, ada baiknya menyimpan ini dalam variabel lingkungan untuk digunakan kembali atau untuk salinan mudah di tempat lain (ini =) ...
realpath
bukan perintah BASH bawaan. Ini adalah executable mandiri yang hanya tersedia di distribusi tertentu
Di bash
Anda bisa mendapatkan nama file skrip menggunakan $0
. Biasanya $1
, $2
dll untuk mengakses argumen CLI. Demikian pula $0
untuk mengakses nama yang memicu skrip (nama file skrip).
#!/bin/bash
echo "You are running $0"
...
...
Jika Anda memanggil skrip dengan path seperti /path/to/script.sh
maka $0
juga akan memberikan nama file dengan path. Dalam hal ini perlu digunakan $(basename $0)
untuk mendapatkan hanya nama file skrip.
$0
tidak menjawab pertanyaan (seperti yang saya mengerti). Demonstrasi:
$ cat script.sh #! / bin / sh echo `basename $ 0` $ ./script.sh script.sh $ ln script.sh linktoscript $ ./linktoscript linktoscript
Bagaimana cara ./linktoscript
mencetak script.sh
?
[EDIT] Per @ephemient dalam komentar di atas, meskipun hal tautan simbolis tampaknya dibuat-buat, dimungkinkan untuk mengutak-atik $0
sedemikian rupa sehingga tidak mewakili sumber daya sistem file. OP agak ambigu tentang apa yang diinginkannya.
Info terima kasih kepada Bill Hernandez. Saya menambahkan beberapa preferensi yang saya adopsi.
#!/bin/bash
function Usage(){
echo " Usage: show_parameters [ arg1 ][ arg2 ]"
}
[[ ${#2} -eq 0 ]] && Usage || {
echo
echo "# arguments called with ----> ${@} "
echo "# \$1 -----------------------> $1 "
echo "# \$2 -----------------------> $2 "
echo "# path to me ---------------> ${0} " | sed "s/$USER/\$USER/g"
echo "# parent path --------------> ${0%/*} " | sed "s/$USER/\$USER/g"
echo "# my name ------------------> ${0##*/} "
echo
}
Bersulang
Singkat, jelas dan sederhana, dalam my_script.sh
#!/bin/bash
running_file_name=$(basename "$0")
echo "You are running '$running_file_name' file."
Keluarkan:
./my_script.sh
You are running 'my_script.sh' file.
DIRECTORY=$(cd `dirname $0` && pwd)
Saya mendapatkan pertanyaan di atas dari pertanyaan Stack Overflow lainnya, Bisakah skrip Bash memberi tahu direktori tempat menyimpannya? , tapi saya pikir ini berguna untuk topik ini juga.
Inilah yang saya kemukakan , diilhami oleh jawaban Dimitre Radoulov (yang saya sampaikan, dengan cara) .
script="$BASH_SOURCE"
[ -z "$BASH_SOURCE" ] && script="$0"
echo "Called $script with $# argument(s)"
terlepas dari cara Anda memanggil skrip Anda
. path/to/script.sh
atau
./path/to/script.sh
sesuatu seperti ini?
export LC_ALL=en_US.UTF-8
#!/bin/bash
#!/bin/sh
#----------------------------------------------------------------------
start_trash(){
ver="htrash.sh v0.0.4"
$TRASH_DIR # url to trash $MY_USER
$TRASH_SIZE # Show Trash Folder Size
echo "Would you like to empty Trash [y/n]?"
read ans
if [ $ans = y -o $ans = Y -o $ans = yes -o $ans = Yes -o $ans = YES ]
then
echo "'yes'"
cd $TRASH_DIR && $EMPTY_TRASH
fi
if [ $ans = n -o $ans = N -o $ans = no -o $ans = No -o $ans = NO ]
then
echo "'no'"
fi
return $TRUE
}
#-----------------------------------------------------------------------
start_help(){
echo "HELP COMMANDS-----------------------------"
echo "htest www open a homepage "
echo "htest trash empty trash "
return $TRUE
} #end Help
#-----------------------------------------------#
homepage=""
return $TRUE
} #end cpdebtemp
# -Case start
# if no command line arg given
# set val to Unknown
if [ -z $1 ]
then
val="*** Unknown ***"
elif [ -n $1 ]
then
# otherwise make first arg as val
val=$1
fi
# use case statement to make decision for rental
case $val in
"trash") start_trash ;;
"help") start_help ;;
"www") firefox $homepage ;;
*) echo "Sorry, I can not get a $val for you!";;
esac
# Case stop