ฉันจะกำหนดชื่อของไฟล์สคริปต์ Bash ภายในสคริปต์ได้อย่างไร
เช่นถ้าสคริปต์ของฉันอยู่ในไฟล์runme.sh
ฉันจะทำให้มันแสดงข้อความ "คุณกำลังเรียกใช้ runme.sh" ได้อย่างไรโดยไม่ต้องใช้ hardcoding
ฉันจะกำหนดชื่อของไฟล์สคริปต์ Bash ภายในสคริปต์ได้อย่างไร
เช่นถ้าสคริปต์ของฉันอยู่ในไฟล์runme.sh
ฉันจะทำให้มันแสดงข้อความ "คุณกำลังเรียกใช้ runme.sh" ได้อย่างไรโดยไม่ต้องใช้ hardcoding
คำตอบ:
me=`basename "$0"`
สำหรับการอ่านผ่าน symlink 1ซึ่งโดยปกติจะไม่ใช่สิ่งที่คุณต้องการ (โดยปกติคุณไม่ต้องการให้ผู้ใช้สับสนด้วยวิธีนี้) ให้ลอง:
me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
IMO ซึ่งจะสร้างผลลัพธ์ที่สับสน "ฉันวิ่ง foo.sh, แต่มันบอกว่าฉันกำลังใช้ bar.sh!? ต้องเป็นบั๊ก!" นอกจากนี้หนึ่งในวัตถุประสงค์ของการมี symlink ที่มีชื่อต่างกันคือการจัดเตรียมการทำงานที่แตกต่างกันตามชื่อที่เรียกว่า (คิดว่า gzip และ gunzip ในบางแพลตฟอร์ม)
1นั่นคือการ symlinks แก้ปัญหาดังกล่าวว่าเมื่อผู้ใช้รันfoo.sh
ซึ่งเป็นจริง symlink ไปbar.sh
คุณต้องการที่จะใช้ชื่อแก้ไขมากกว่าbar.sh
foo.sh
$0
ในตัวอย่างแรกนั้นขึ้นอยู่กับการแบ่งคำ 3. $0
จะถูกส่งผ่านไปยัง basename, readlink และ echo ในตำแหน่งที่อนุญาตให้ถือว่าเป็นสวิตช์บรรทัดคำสั่ง . ฉันแนะนำแทนme=$(basename -- "$0")
หรืออย่างมีประสิทธิภาพมากกว่าที่ค่าใช้จ่ายในการอ่าน, me=${0##*/}
. สำหรับ symlink me=$(basename -- "$(readlink -f -- "$0")")
สมมติว่า gnu utils มิฉะนั้นจะเป็นสคริปต์ที่ยาวมากซึ่งฉันจะไม่เขียนที่นี่
# ------------- SCRIPT ------------- # # ------------- CALLED ------ ------- #
#!/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
# ประกาศในบรรทัดถัดไปอาร์กิวเมนต์แรกถูกเรียกใช้ภายใน double, # และเครื่องหมายอัญประกาศเดี่ยวเนื่องจากมีสองคำ
$ / เบ็ดเตล็ด/ shell_scripts / check_root / show_parms sh "'hello there'" "'william'"
# ------------- ผล ------------- #
# อาร์กิวเมนต์ที่เรียกด้วย ---> 'สวัสดีนั่น' 'วิลเลียม' # $ 1 ----------------------> 'สวัสดีที่นั่น' # $ 2 ---- ------------------> เส้นทาง'วิลเลียม' # มาหาฉัน --------------> / misc / shell_scripts / check_root / show_parms sh # พา ธ หลัก -------------> / misc / shell_scripts / check_root # ชื่อของฉัน -----------------> show_parms.sh
# ------------- END ------------- #
show_params
ชื่อคือไม่มีนามสกุลไม่จำเป็น?
${0##*/}
เส้นทางดังกล่าวจะรวมอยู่ใน ผ่านการทดสอบโดยใช้ GitBash
ด้วยbash> = 3งานต่อไปนี้:
$ ./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
" เพื่อรับไดเรกทอรีที่ตั้งสคริปต์
$BASH_SOURCE
ให้คำตอบที่ถูกต้องเมื่อทำการจัดหาสคริปต์
ซึ่งรวมถึงเส้นทางเพื่อให้ได้รับชื่อไฟล์สคริปต์เท่านั้นใช้:
$(basename $BASH_SOURCE)
. <filename> [arguments]
, $0
จะให้ชื่อของเปลือกโทร อย่างน้อยใน OSX อย่างแน่นอน
หากชื่อสคริปต์ที่มีช่องว่างในมันเป็นวิธีที่มีประสิทธิภาพมากขึ้นคือการใช้"$0"
หรือ"$(basename "$0")"
- หรือบน "$(basename \"$0\")"
MacOS: สิ่งนี้จะป้องกันไม่ให้ชื่อถูกจัดการหรือตีความในทางใดทางหนึ่ง โดยทั่วไปแล้วมันเป็นการดีที่จะใช้ชื่อตัวแปรอัญประกาศคู่เสมอในเชลล์
หากต้องการตอบChris Conwayบน Linux (อย่างน้อย) คุณต้องทำสิ่งนี้:
echo $(basename $(readlink -nf $0))
readlink พิมพ์ค่าของลิงก์สัญลักษณ์ หากไม่ใช่ลิงค์สัญลักษณ์จะพิมพ์ชื่อไฟล์ -n บอกให้ไม่พิมพ์บรรทัดใหม่ - f บอกให้ติดตามลิงก์อย่างสมบูรณ์ (หากลิงก์สัญลักษณ์เป็นลิงก์ไปยังลิงก์อื่นก็จะแก้ไขได้เช่นกัน)
ฉันพบว่าบรรทัดนี้ใช้งานได้เสมอโดยไม่คำนึงว่าไฟล์นั้นมีแหล่งที่มาหรือเรียกใช้เป็นสคริปต์
echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
หากคุณต้องการติดตามการใช้ symlink readlink
บนเส้นทางที่คุณได้รับด้านบนเรียกซ้ำหรือไม่เรียกซ้ำ
เหตุผลหนึ่งซับการทำงานจะมีการอธิบายจากการใช้งานของBASH_SOURCE
ตัวแปรสภาพแวดล้อมและ FUNCNAME
บริษัท ร่วม
BASH_SOURCE
ตัวแปรอาร์เรย์ที่สมาชิกเป็นชื่อไฟล์ต้นทางที่ชื่อฟังก์ชันเชลล์ที่สอดคล้องกันในตัวแปรอาร์เรย์ FUNCNAME ถูกกำหนดไว้ ฟังก์ชันเชลล์ $ {FUNCNAME [$ i]} ถูกกำหนดไว้ในไฟล์ $ {BASH_SOURCE [$ i]} และเรียกใช้จาก $ {BASH_SOURCE [$ i + 1]}
FUNCNAME
ตัวแปรอาร์เรย์ที่มีชื่อของฟังก์ชั่นเชลล์ทั้งหมดในปัจจุบันในการเรียกการเรียกใช้งาน องค์ประกอบที่มีดัชนี 0 เป็นชื่อของฟังก์ชั่นเปลือกที่กำลังดำเนินการใด ๆ ในปัจจุบัน องค์ประกอบด้านล่างสุด (องค์ประกอบที่มีดัชนีสูงสุด) คือ "หลัก" ตัวแปรนี้มีอยู่เฉพาะเมื่อมีการเรียกใช้ฟังก์ชันเชลล์ การกำหนดให้กับ FUNCNAME ไม่มีผลกระทบและส่งคืนสถานะข้อผิดพลาด หาก FUNCNAME ไม่ได้ตั้งค่ามันจะสูญเสียคุณสมบัติพิเศษแม้ว่าจะถูกรีเซ็ตในภายหลัง
ตัวแปรนี้สามารถใช้กับ BASH_LINENO และ BASH_SOURCE แต่ละองค์ประกอบของ FUNCNAME มีองค์ประกอบที่สอดคล้องกันใน BASH_LINENO และ BASH_SOURCE เพื่ออธิบายสายการโทร ตัวอย่างเช่น $ {FUNCNAME [$ i]} ถูกเรียกจากไฟล์ $ {BASH_SOURCE [$ i + 1]} ที่หมายเลขบรรทัด $ {BASH_LINENO [$ i]} ตัวเรียกในตัวแสดงสแต็กการโทรปัจจุบันโดยใช้ข้อมูลนี้
[ที่มา: คู่มือทุบตี]
a
(ถือว่าa
เนื้อหาเป็นecho "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
) จากเซสชั่นแบบโต้ตอบ - แล้วมันจะให้a
เส้นทางของคุณ แต่ถ้าคุณเขียนสคริปต์b
ที่มีsource a
อยู่ในนั้นและเรียกใช้./b
ก็จะกลับมาb
's เส้นทาง
คำตอบเหล่านี้ถูกต้องสำหรับกรณีที่พวกเขาระบุ แต่ยังคงมีปัญหาหากคุณเรียกใช้สคริปต์จากสคริปต์อื่นโดยใช้คำหลัก 'แหล่งที่มา' (เพื่อให้มันทำงานในเชลล์เดียวกัน) ในกรณีนี้คุณจะได้รับ $ 0 ของสคริปต์การโทร และในกรณีนี้ฉันไม่คิดว่าเป็นไปได้ที่จะได้ชื่อของสคริปต์นั้น
นี่เป็นกรณีที่ไม่ควรนำมาใช้อย่างจริงจัง หากคุณเรียกใช้สคริปต์จากสคริปต์อื่นโดยตรง (โดยไม่มี 'แหล่งที่มา') การใช้ $ 0 จะใช้งานได้
เนื่องจากความคิดเห็นบางส่วนถามเกี่ยวกับชื่อไฟล์ที่ไม่มีนามสกุลนี่คือตัวอย่างวิธีการทำให้สำเร็จ:
FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}
สนุก!
Re: คำตอบของ Tanktalus (เป็นที่ยอมรับ) ข้างต้นวิธีใช้ที่สะอาดกว่านี้เล็กน้อย:
me=$(readlink --canonicalize --no-newline $0)
หากสคริปต์ของคุณได้มาจากสคริปต์ทุบตีอื่นคุณสามารถใช้:
me=$(readlink --canonicalize --no-newline $BASH_SOURCE)
ฉันยอมรับว่ามันอาจสร้างความสับสนในการยกเลิกการเชื่อมโยงหากวัตถุประสงค์ของคุณคือการให้ข้อเสนอแนะกับผู้ใช้ แต่มีหลายครั้งที่คุณจำเป็นต้องได้รับชื่อมาตรฐานจากสคริปต์หรือไฟล์อื่น ๆ และนี่คือวิธีที่ดีที่สุด
source
ชื่อสคริปต์
คุณสามารถใช้ $ 0 เพื่อกำหนดชื่อสคริปต์ของคุณ (พร้อมเส้นทางแบบเต็ม) - เพื่อให้ได้ชื่อสคริปต์เท่านั้นคุณสามารถตัดตัวแปรนั้นด้วย
basename $0
ถ้าคุณเรียกใช้สคริปต์เปลือกเช่น
/home/mike/runme.sh
$ 0 เป็นชื่อเต็ม
/home/mike/runme.sh
basename $ 0 จะได้รับชื่อไฟล์ฐาน
runme.sh
และคุณต้องใส่ชื่อพื้นฐานนี้ลงในตัวแปรเช่น
filename=$(basename $0)
และเพิ่มข้อความเพิ่มเติมของคุณ
echo "You are running $filename"
ดังนั้นสคริปต์ของคุณชอบ
/home/mike/runme.sh
#!/bin/bash
filename=$(basename $0)
echo "You are running $filename"
this="$(dirname "$(realpath "$BASH_SOURCE")")"
สิ่งนี้จะแก้ไขลิงก์สัญลักษณ์ (realpath ทำเช่นนั้น) จัดการช่องว่าง (อัญประกาศทำสิ่งนี้) และจะค้นหาชื่อสคริปต์ปัจจุบันแม้ว่าจะมีแหล่งที่มา (./myscript) หรือถูกเรียกโดยสคริปต์อื่น ($ BASH_SOURCE จะจัดการกับสิ่งนั้น) หลังจากนั้นก็เป็นการดีที่จะบันทึกสิ่งนี้ไว้ในตัวแปรสภาพแวดล้อมเพื่อนำกลับมาใช้ใหม่หรือคัดลอกได้ง่ายที่อื่น (this =) ...
realpath
ไม่ใช่คำสั่ง BASH ในตัว มันเป็นปฏิบัติการแบบสแตนด์อโลนที่มีเฉพาะในการแจกแจงบางอย่าง
ในคุณจะได้รับชื่อไฟล์สคริปต์ที่ใช้bash
$0
โดยทั่วไป$1
แล้ว$2
การเข้าถึงข้อโต้แย้งของ CLI ในทำนองเดียวกัน$0
คือการเข้าถึงชื่อที่เรียกสคริปต์ (ชื่อไฟล์สคริปต์)
#!/bin/bash
echo "You are running $0"
...
...
หากคุณเรียกใช้สคริปต์ด้วยเส้นทางเช่น/path/to/script.sh
นั้น$0
ก็จะให้ชื่อไฟล์ที่มีเส้นทาง ในกรณีนั้นจำเป็นต้องใช้$(basename $0)
เพื่อรับชื่อไฟล์สคริปต์เท่านั้น
echo "$(basename "`test -L ${BASH_SOURCE[0]} \
&& readlink ${BASH_SOURCE[0]} \
|| echo ${BASH_SOURCE[0]}`")"
$0
ไม่ตอบคำถาม (ตามที่ฉันเข้าใจ) การสาธิต:
$ cat script.sh #! bin / sh / echo `basename $ 0` $ ./script.sh script.sh $ ln script.sh linktoscript $ ./linktoscript linktoscript
เรา./linktoscript
จะพิมพ์ออกมาได้script.sh
อย่างไร
[แก้ไข] ต่อ @ephemient ในความคิดเห็นด้านบนถึงแม้ว่าสิ่งที่เชื่อมโยงสัญลักษณ์อาจดูเหมือนว่าถูกประดิษฐ์ขึ้น แต่ก็เป็นไปได้ที่จะทำ$0
เช่นนี้โดยไม่ได้แสดงถึงทรัพยากรระบบแฟ้ม OP ค่อนข้างคลุมเครือเกี่ยวกับสิ่งที่เขาต้องการ
ข้อมูลขอบคุณ Bill Hernandez ฉันได้เพิ่มการตั้งค่าบางอย่างที่ฉันยอมรับ
#!/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
}
ไชโย
สั้นชัดเจนและเรียบง่ายมา my_script.sh
#!/bin/bash
running_file_name=$(basename "$0")
echo "You are running '$running_file_name' file."
ออกวาง:
./my_script.sh
You are running 'my_script.sh' file.
DIRECTORY=$(cd `dirname $0` && pwd)
ฉันได้รับคำถามข้างต้นจาก Stack Overflow คำถามสคริปต์ Bash สามารถบอกได้ว่าไดเรกทอรีใดเก็บไว้ใน แต่ฉันคิดว่ามันมีประโยชน์สำหรับหัวข้อนี้เช่นกัน
นี่คือสิ่งที่ฉันมาด้วยแรงบันดาลใจจากDimitre Radoulovคำตอบ 's (ซึ่งผม upvoted โดยวิธีการ)
script="$BASH_SOURCE"
[ -z "$BASH_SOURCE" ] && script="$0"
echo "Called $script with $# argument(s)"
ไม่ว่าคุณจะเรียกสคริปต์ของคุณอย่างไร
. path/to/script.sh
หรือ
./path/to/script.sh
อะไรแบบนี้?
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