ฉันจะตรวจสอบว่าโปรแกรมมีอยู่ในวิธีที่จะส่งคืนข้อผิดพลาดและออกหรือดำเนินการต่อกับสคริปต์ได้อย่างไร
ดูเหมือนว่ามันควรจะง่าย แต่มันทำให้ฉันนิ่งงัน
ฉันจะตรวจสอบว่าโปรแกรมมีอยู่ในวิธีที่จะส่งคืนข้อผิดพลาดและออกหรือดำเนินการต่อกับสคริปต์ได้อย่างไร
ดูเหมือนว่ามันควรจะง่าย แต่มันทำให้ฉันนิ่งงัน
คำตอบ:
รองรับ POSIX:
command -v <the_command>
สำหรับสภาพแวดล้อมเฉพาะของ Bash:
hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords
which
หลีกเลี่ยงการ ไม่เพียง แต่มันเป็นกระบวนการภายนอกที่คุณกำลังเปิดตัวสำหรับการทำน้อยมาก (builtins หมายถึงชอบhash
, type
หรือcommand
มีวิธีที่ถูกกว่า) นอกจากนี้คุณยังสามารถพึ่งพา builtins ที่จริงทำในสิ่งที่คุณต้องการในขณะที่ผลกระทบจากคำสั่งภายนอกอาจแตกต่างกันได้อย่างง่ายดายจาก ระบบต่อระบบ
ทำไมต้องแคร์
which
ที่ไม่ได้ตั้งสถานะทางออกหมายถึงif which foo
จะไม่ได้ทำงานที่นั่นและจะเสมอรายงานว่าfoo
มีอยู่ถึงแม้ว่ามันจะไม่ได้ (หมายเหตุว่าบางหอย POSIX ปรากฏว่าทำเช่นนี้สำหรับhash
เกินไป)which
สิ่งที่กำหนดเองและสิ่งที่ชั่วร้ายเช่นเปลี่ยนผลลัพธ์หรือแม้แต่ขอตัวจัดการแพคเกจwhich
ดังนั้นไม่ได้ใช้ ใช้หนึ่งในเหล่านี้แทน:
$ command -v foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed. Aborting."; exit 1; }
$ type foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed. Aborting."; exit 1; }
$ hash foo 2>/dev/null || { echo >&2 "I require foo but it's not installed. Aborting."; exit 1; }
(ไมเนอร์ด้านหมายเหตุ: บางคนจะแนะนำ2>&-
เป็นเหมือนกัน2>/dev/null
แต่สั้น - นี้เป็นความจริง . 2>&-
ปิด FD 2 ซึ่งทำให้เกิดข้อผิดพลาดในโปรแกรมเมื่อพยายามที่จะเขียนถึง stderr ซึ่งแตกต่างกันมากประสบความสำเร็จจากการเขียนไปและทิ้งเอาท์พุท (และอันตราย!)
หากแฮชปังของคุณคือ/bin/sh
สิ่งที่คุณควรใส่ใจกับสิ่งที่ POSIX พูด type
และhash
รหัสการออกของยังไม่ได้กำหนดไว้อย่างดีเยี่ยมโดย POSIX และhash
จะเห็นว่าการออกสำเร็จเมื่อคำสั่งยังไม่มีอยู่ (ยังไม่เห็นสิ่งนี้ด้วยtype
) command
สถานะการออกของ POSIX นั้นกำหนดไว้อย่างดีดังนั้นจึงน่าจะเป็นวิธีที่ปลอดภัยที่สุดที่จะใช้
หากใช้สคริปต์ของคุณbash
แม้ว่ากฎ POSIX ไม่ได้เรื่องจริงๆอีกต่อไปและทั้งสองtype
และhash
กลายเป็นที่ที่ดีที่สุดที่ปลอดภัยในการใช้งาน type
ตอนนี้มีการ-P
ค้นหาเพียงแค่PATH
และhash
มีผลข้างเคียงที่ตำแหน่งของคำสั่งจะถูกแฮช (สำหรับการค้นหาได้เร็วขึ้นในครั้งต่อไปที่คุณใช้) ซึ่งมักจะเป็นสิ่งที่ดีเพราะคุณอาจตรวจสอบการมีอยู่ของมันเพื่อใช้งานจริง .
ตัวอย่างง่ายๆนี่คือฟังก์ชั่นที่จะทำงานgdate
หากมีอยู่มิฉะนั้นdate
:
gnudate() {
if hash gdate 2>/dev/null; then
gdate "$@"
else
date "$@"
fi
}
2>&-
("ไฟล์คำอธิบายปิดเอาต์พุต 2" ซึ่งเป็น stderr)มีผลลัพธ์แบบเดียวกันกับ2> /dev/null
; 2) >&2
เป็นทางลัด1>&2
ซึ่งคุณอาจจำได้ว่าเป็น "เปลี่ยนเส้นทาง stdout ไปยัง stderr" ดูหน้าการเปลี่ยนเส้นทางคำแนะนำการเขียนสคริปต์ Bash ขั้นสูงสำหรับข้อมูลเพิ่มเติม
while read element ; do .. done <<< $(echo ${ArrayVar[*]})
, for word in $(fgrep -l $ORIGINAL *.txt)
, ls -l "$directory" | sed 1d
{{สำหรับในseq $BEGIN $END
}} ... หลายคนได้พยายามที่จะติดต่อผู้เขียนและนำเสนอการปรับปรุง แต่ก็ไม่มีวิกิพีเดียและการร้องขอมีที่ดินบนหูหนวก
2>&-
คือไม่ได้2>/dev/null
เช่นเดียวกับ /dev/null
อดีตปิดอธิบายไฟล์ในขณะที่หลังจะเปลี่ยนเส้นทางไปยัง คุณอาจไม่เห็นข้อผิดพลาดเนื่องจากโปรแกรมพยายามแจ้งให้คุณทราบถึง stderr ว่า stderr ถูกปิด
ต่อไปนี้เป็นวิธีพกพาเพื่อตรวจสอบว่ามีคำสั่งอยู่หรือไม่$PATH
และสามารถทำงานได้:
[ -x "$(command -v foo)" ]
ตัวอย่าง:
if ! [ -x "$(command -v git)" ]; then
echo 'Error: git is not installed.' >&2
exit 1
fi
$PATH
การตรวจสอบการปฏิบัติการเป็นสิ่งจำเป็นเพราะทุบตีส่งกลับไฟล์ไม่สามารถทำงานได้หากไม่มีแฟ้มที่ปฏิบัติการด้วยชื่อที่พบใน
นอกจากนี้โปรดทราบว่าหากไฟล์ที่ไม่สามารถเรียกใช้งานได้ซึ่งมีชื่อเดียวกันกับไฟล์ที่เรียกทำงานได้มีอยู่ก่อนหน้านี้$PATH
Dash จะส่งคืนไฟล์เดิมแม้ว่าไฟล์ดังกล่าวจะถูกเรียกใช้งานก็ตาม นี่เป็นข้อผิดพลาดและละเมิดมาตรฐาน POSIX [ รายงานข้อผิดพลาด ] [ มาตรฐาน ]
นอกจากนี้สิ่งนี้จะล้มเหลวหากคำสั่งที่คุณต้องการถูกกำหนดเป็นนามแฝง
command -v
สร้างเส้นทางแม้แต่ไฟล์ที่ไม่สามารถเรียกใช้งานได้หรือไม่ นั่นคือ -x จำเป็นจริงๆเหรอ?
-x
ทดสอบว่าไฟล์นั้นสามารถเรียกใช้งานได้ซึ่งเป็นปัญหาที่เกิดขึ้น
command
ตัวเองจะทดสอบสำหรับการปฏิบัติการ - จะไม่ได้หรือไม่
$PATH
เมื่อเรียกใช้คำสั่ง อย่างไรก็ตามพฤติกรรมของcommand -v
ไม่สอดคล้องกันมาก ในเส้นประมันจะส่งคืนไฟล์แรกที่จับคู่เข้า$PATH
มาโดยไม่คำนึงว่าสามารถเรียกใช้งานได้หรือไม่ ใน bash จะส่งคืนการจับคู่ที่เรียกใช้งานได้ครั้งแรก$PATH
แต่ถ้าไม่มีจะสามารถส่งคืนไฟล์ที่ไม่สามารถเรียกทำงานได้ และใน zsh มันจะไม่ส่งคืนไฟล์ที่ไม่สามารถเรียกใช้งานได้
dash
มีเพียงหนึ่งในสามที่ไม่สอดคล้องกับ POSIX [ -x "$(command -v COMMANDNAME)"]
จะทำงานในอีกสองคน ดูเหมือนว่าข้อผิดพลาดนี้ได้รับการรายงานแล้ว แต่ยังไม่ได้รับคำตอบใด ๆ : bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264
ผมเห็นด้วยกับ lhunath ที่จะกีดกันการใช้which
และวิธีการแก้ปัญหาของเขาคือการที่ถูกต้องสมบูรณ์สำหรับผู้ใช้ทุบตี อย่างไรก็ตามเพื่อให้พกพาได้มากกว่าcommand -v
ให้ใช้แทน:
$ command -v foo >/dev/null 2>&1 || { echo "I require foo but it's not installed. Aborting." >&2; exit 1; }
คำสั่งcommand
สอดคล้องกับ POSIX ดูที่นี่สำหรับข้อมูลจำเพาะ: คำสั่ง - รันคำสั่งแบบง่าย
บันทึก: type
เป็นไปตาม POSIX แต่type -P
ไม่ใช่
exit 1;
ฆ่า xterm ถ้าถูกเรียกจากที่นั่น
&>/dev/null
จึงเปลี่ยนเส้นทางสัญกรณ์ทุบตีเฉพาะรัดกุมมากขึ้น >/dev/null 2>&1
แต่ผมเห็นด้วยกับคุณจริงๆสิ่งที่สำคัญก็คือการพกพาผมได้แก้ไขคำตอบของฉันดังนั้นตอนนี้ใช้การเปลี่ยนเส้นทางการดวลจุดโทษมาตรฐาน
ฉันมีฟังก์ชั่นที่กำหนดไว้ใน. bashrc ของฉันซึ่งทำให้ง่ายขึ้น
command_exists () {
type "$1" &> /dev/null ;
}
นี่คือตัวอย่างการใช้งาน (จากของฉัน.bash_profile
)
if command_exists mvim ; then
export VISUAL="mvim --nofork"
fi
&>
ทำอย่างไร
&>
เปลี่ยนเส้นทางทั้ง stdout และ stderrด้วยกัน
&>
อาจไม่สามารถใช้ได้ใน Bash เวอร์ชันของคุณ รหัสของ Marcello ควรทำงานได้ดี มันทำสิ่งเดียวกัน
ขึ้นอยู่กับว่าคุณต้องการทราบว่ามีอยู่ในหนึ่งในไดเรกทอรีใน$PATH
ตัวแปรหรือไม่หรือคุณทราบตำแหน่งที่แน่นอนของมัน หากคุณต้องการทราบว่าอยู่ใน$PATH
ตัวแปรหรือไม่ให้ใช้
if which programname >/dev/null; then
echo exists
else
echo does not exist
fi
มิฉะนั้นใช้
if [ -x /path/to/programname ]; then
echo exists
else
echo does not exist
fi
การเปลี่ยนเส้นทางไปยัง/dev/null/
ในตัวอย่างแรกจะไม่แสดงผลลัพธ์ของwhich
โปรแกรม
การขยายคำตอบของ @ lhunath และ @ GregV ต่อไปนี้เป็นรหัสสำหรับผู้ที่ต้องการนำการตรวจสอบนั้นออกมาอย่างง่ายดายในif
คำสั่ง:
exists()
{
command -v "$1" >/dev/null 2>&1
}
นี่คือวิธีการใช้งาน:
if exists bash; then
echo 'Bash exists!'
else
echo 'Your system does not have Bash'
fi
command
ประสบความสำเร็จแม้สำหรับนามแฝงซึ่งอาจจะค่อนข้างใช้งานง่าย การตรวจสอบว่ามีอยู่ในเชลล์แบบโต้ตอบจะให้ผลลัพธ์ที่แตกต่างจากเมื่อคุณย้ายมันไปที่สคริปต์
shopt -u expand_aliases
ละเว้น / กลองนามแฝง (เหมือนalias ls='ls -F'
ที่กล่าวไว้ในคำตอบอื่น) และแก้ไขพวกเขาผ่านทางshopt -s expand_aliases
command -v
ดังนั้นจึงควรตั้งค่าก่อนการตรวจสอบและยกเลิกการตั้งค่าแม้ว่ามันอาจส่งผลกระทบต่อค่าส่งคืนฟังก์ชั่นถ้าคุณไม่ได้จับและส่งกลับผลลัพธ์ของการเรียกคำสั่งอย่างชัดเจน
ลองใช้:
test -x filename
หรือ
[ -x filename ]
จาก Bash manpage ภายใต้การแสดงออกแบบมีเงื่อนไข :
-x file True if file exists and is executable.
หากต้องการใช้hash
, เป็น @lhunath แสดงให้เห็นในสคริปต์ทุบตี:
hash foo &> /dev/null
if [ $? -eq 1 ]; then
echo >&2 "foo not found."
fi
สคริปต์นี้วิ่งhash
และการตรวจสอบแล้วถ้ารหัสทางออกของคำสั่งล่าสุดค่าที่เก็บไว้ในเท่ากับ$?
1
หากhash
ไม่พบรหัสทางออกจะเป็นfoo
1
ถ้าเป็นปัจจุบันรหัสทางออกจะเป็นfoo
0
&> /dev/null
เปลี่ยนเส้นทางข้อผิดพลาดมาตรฐานและเอาต์พุตมาตรฐานจากhash
เพื่อไม่ให้ปรากฏบนหน้าจอและecho >&2
เขียนข้อความไปยังข้อผิดพลาดมาตรฐาน
if hash foo &> /dev/null; then ...
?
ฉันไม่เคยได้รับคำตอบก่อนหน้านี้มาทำงานในกล่องที่ฉันสามารถเข้าถึงได้ สำหรับหนึ่งtype
ได้รับการติดตั้ง (ทำในสิ่งที่ทำmore
) ดังนั้นจึงจำเป็นต้องมีคำสั่งในตัว คำสั่งนี้ใช้ได้สำหรับฉัน:
if [ `builtin type -p vim` ]; then echo "TRUE"; else echo "FALSE"; fi
if
if builtin type -p vim; then ...
และ backticks นั้นมีความเก่าแก่และซินแท็คซ์ที่$()
ได้รับการสนับสนุนแม้กระทั่งsh
ในระบบที่ทันสมัยทั้งหมด
ตรวจสอบการอ้างอิงหลายรายการและแจ้งสถานะแก่ผู้ใช้ปลายทาง
for cmd in latex pandoc; do
printf '%-10s' "$cmd"
if hash "$cmd" 2>/dev/null; then
echo OK
else
echo missing
fi
done
ตัวอย่างผลลัพธ์:
latex OK
pandoc missing
ปรับ10
ความยาวสูงสุดของคำสั่ง มันไม่อัตโนมัติเพราะฉันไม่เห็นวิธี POSIX แบบไม่ต้องทำ:
ฉันจะจัดแนวคอลัมน์ของตารางที่คั่นด้วยช่องว่างใน Bash ได้อย่างไร
ตรวจสอบว่าapt
มีการติดตั้งแพคเกจบางอย่างdpkg -s
และติดตั้งหรือไม่
ดู: ตรวจสอบว่ามีการติดตั้งแพกเกจ apt-get หรือไม่จากนั้นติดตั้งหากไม่ได้อยู่ใน Linux
ก่อนหน้านี้ถูกกล่าวถึงที่: ฉันจะตรวจสอบว่าโปรแกรมนั้นมีอยู่จากสคริปต์ Bash ได้อย่างไร
column -t
(ส่วนหนึ่งของ util-linux)
หากคุณตรวจสอบการมีอยู่ของโปรแกรมคุณอาจจะเรียกใช้ในภายหลัง ทำไมไม่ลองใช้มันตั้งแต่แรกล่ะ?
if foo --version >/dev/null 2>&1; then
echo Found
else
echo Not found
fi
เป็นการตรวจสอบที่น่าเชื่อถือมากขึ้นว่าโปรแกรมทำงานได้ดีกว่าเพียงแค่ดูที่ไดเรกทอรีเส้นทางและการอนุญาตไฟล์
ยิ่งไปกว่านั้นคุณจะได้รับผลลัพธ์ที่เป็นประโยชน์จากโปรแกรมของคุณเช่นเวอร์ชันของมัน
แน่นอนว่าข้อเสียคือบางโปรแกรมอาจเริ่มทำงานหนักและบางโปรแกรมไม่มี--version
ตัวเลือกในการออกจาก (ทันทีและสำเร็จ)
hash foo 2>/dev/null
: ทำงานร่วมกับ Z shell (Zsh), Bash, Dashและashเถ้า
type -p foo
: ดูเหมือนว่าจะทำงานกับ Z shell, Bash and ash ( BusyBox ) แต่ไม่ใช่ Dash (แปลว่ามัน-p
เป็นอาร์กิวเมนต์)
command -v foo
: ทำงานร่วมกับ Z shell, Bash, Dash, แต่ไม่ใช่ Ash (BusyBox) (-ash: command: not found
)
โปรดทราบว่าbuiltin
ไม่สามารถใช้ได้กับเถ้าและเส้นประ
ใช้ Bash builtins หากคุณสามารถ:
which programname
...
type -P programname
which
ไม่ใช่ Bash builtin
-P
คือไม่ใช่ POSIX ทำไมถึงtype -P
เลือก?
คำสั่ง-v
ทำงานได้ดีหากตั้งค่าตัวเลือก POSIX_BUILTINS ไว้สำหรับ<command>
ทดสอบ แต่จะล้มเหลวได้หากไม่ได้ (มันใช้งานได้สำหรับฉันมาหลายปีแล้ว แต่ฉันเพิ่งพบเจอสิ่งที่ไม่ได้ผล)
ฉันพบว่าสิ่งต่อไปนี้จะล้มเหลวได้มากกว่านี้:
test -x $(which <command>)
เนื่องจากเป็นการทดสอบสามสิ่ง: เส้นทางการมีอยู่และการอนุญาตให้ดำเนินการ
test -x $(which ls)
ผลตอบแทน 0 เช่นเดียวtest -x $(which sudo)
แม้ว่าจะls
มีการติดตั้งและทำงานได้และsudo
ไม่ได้ติดตั้งแม้จะอยู่ในภาชนะนักเทียบท่าที่ผมกำลังทำงานใน.
test -x "$(which <command>)"
ls
เป็นนามแฝงหรือไม่ ฉันไม่คิดว่ามันจะทำงานถ้าคำสั่งมีพารามิเตอร์
สำหรับผู้ที่สนใจไม่มีวิธีการในคำตอบก่อนหน้านี้ทำงานถ้าคุณต้องการตรวจสอบห้องสมุดที่ติดตั้ง ฉันคิดว่าคุณถูกทิ้งอย่างใดอย่างหนึ่งด้วยการตรวจสอบเส้นทาง (อาจเป็นไฟล์ส่วนหัวและอื่น ๆ ) หรือสิ่งนี้ (ถ้าคุณใช้การกระจายแบบ Debian):
dpkg --status libdb-dev | grep -q not-installed
if [ $? -eq 0 ]; then
apt-get install libdb-dev
fi
ดังที่คุณเห็นจากด้านบนคำตอบ "0" จากแบบสอบถามหมายความว่าไม่ได้ติดตั้งแพ็คเกจ นี่คือฟังก์ชั่นของ "grep" - "0" หมายถึงพบการแข่งขัน "1" หมายถึงไม่พบการแข่งขัน
cmd; if [ $? -eq 0 ]; then
ควรได้รับการ refactored ถึงif cmd; then
dpkg
หรือapt
มีตัวเลือกมากมายที่นี่ แต่ฉันรู้สึกประหลาดใจเลยว่าไม่มีซับในอย่างรวดเร็ว นี่คือสิ่งที่ฉันใช้ในตอนต้นของสคริปต์ของฉัน:
[[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1>&2 ; exit 1; }
[[ "$(command -v java)" ]] || { echo "java is not installed" 1>&2 ; exit 1; }
นี่คือคำตอบที่เลือกที่นี่และแหล่งอื่น
ฉันจะบอกว่าไม่มีวิธีการพกพาและเชื่อถือได้ 100% เนื่องจากการห้อยalias
ES ตัวอย่างเช่น:
alias john='ls --color'
alias paul='george -F'
alias george='ls -h'
alias ringo=/
แน่นอนมีเพียงอันสุดท้ายเท่านั้นที่เป็นปัญหา (ไม่มีความผิดต่อริงโก้!) แต่ทั้งหมดของพวกเขาที่ถูกต้องalias
ES command -v
จากมุมมองของ
เพื่อที่จะปฏิเสธคนที่ชอบห้อยringo
เราต้องแยกเอาท์พุทของalias
คำสั่งในตัวของเชลล์และเรียกคืนเข้าไป ( command -v
ไม่ดีกว่าalias
ที่นี่) ไม่มีวิธีแก้ปัญหาแบบพกพาสำหรับมันและแม้แต่ Bash- วิธีแก้ปัญหาเฉพาะค่อนข้างน่าเบื่อ
โปรดทราบว่าวิธีแก้ปัญหาเช่นนี้จะปฏิเสธโดยไม่มีเงื่อนไขalias ls='ls -F'
:
test() { command -v $1 | grep -qv alias }
shopt -u expand_aliases
ละเว้น / ซ่อนชื่อแทนเหล่านี้และแสดงให้เห็นว่าพวกเขาผ่านทางshopt -s expand_aliases
command -v
สิ่งนี้จะบอกตามตำแหน่งหากมีโปรแกรมอยู่หรือไม่:
if [ -x /usr/bin/yum ]; then
echo "This is Centos"
fi
which
คำสั่งอาจจะมีประโยชน์คนที่
มันจะคืนค่า 0 หากพบไฟล์ที่เรียกทำงานได้และส่งคืน 1 หากไม่พบไฟล์ปฏิบัติการหรือไม่:
NAME
which - locate a command
SYNOPSIS
which [-a] filename ...
DESCRIPTION
which returns the pathnames of the files which would
be executed in the current environment, had its
arguments been given as commands in a strictly
POSIX-conformant shell. It does this by searching
the PATH for executable files matching the names
of the arguments.
OPTIONS
-a print all matching pathnames of each argument
EXIT STATUS
0 if all specified commands are
found and executable
1 if one or more specified commands is nonexistent
or not executable
2 if an invalid option is specified
สิ่งที่ดีเกี่ยวกับการwhich
ที่จะระบุว่าปฏิบัติการที่มีอยู่ในสภาพแวดล้อมที่which
ทำงานใน - มันช่วยประหยัดปัญหาบางอย่าง ...
การตั้งค่าของฉันสำหรับDebianเซิร์ฟเวอร์ :
ฉันมีปัญหาเมื่อมีหลายแพ็คเกจที่ใช้ชื่อเดียวกัน
apache2
เช่น ดังนั้นนี่คือทางออกของฉัน:
function _apt_install() {
apt-get install -y $1 > /dev/null
}
function _apt_install_norecommends() {
apt-get install -y --no-install-recommends $1 > /dev/null
}
function _apt_available() {
if [ `apt-cache search $1 | grep -o "$1" | uniq | wc -l` = "1" ]; then
echo "Package is available : $1"
PACKAGE_INSTALL="1"
else
echo "Package $1 is NOT available for install"
echo "We can not continue without this package..."
echo "Exitting now.."
exit 0
fi
}
function _package_install {
_apt_available $1
if [ "${PACKAGE_INSTALL}" = "1" ]; then
if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
echo "package is already_installed: $1"
else
echo "installing package : $1, please wait.."
_apt_install $1
sleep 0.5
fi
fi
}
function _package_install_no_recommends {
_apt_available $1
if [ "${PACKAGE_INSTALL}" = "1" ]; then
if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
echo "package is already_installed: $1"
else
echo "installing package : $1, please wait.."
_apt_install_norecommends $1
sleep 0.5
fi
fi
}
หากคุณ / Gals ไม่สามารถหาคำตอบได้ที่นี่เพื่อทำงานและดึงผมออกจากหลังให้ลองเรียกใช้คำสั่งเดียวกันโดยใช้ bash -c
ไม่สามารถได้รับสิ่งที่อยู่ในคำตอบที่นี่เพื่อทำงานและมีการดึงผมออกมาจากด้านหลังของคุณพยายามที่จะเรียกใช้คำสั่งเดียวกันโดยใช้ เพียงแค่ดูเพ้อเพ้อนามนี้ นี่คือสิ่งที่เกิดขึ้นจริงเมื่อคุณเรียกใช้ $ (คำสั่งย่อย):
เป็นครั้งแรก มันสามารถให้ผลลัพธ์ที่แตกต่างอย่างสิ้นเชิง
$ command -v ls
alias ls='ls --color=auto'
$ bash -c "command -v ls"
/bin/ls
ที่สอง มันสามารถให้ผลลัพธ์ที่ไม่มีเลย
$ command -v nvm
nvm
$ bash -c "command -v nvm"
$ bash -c "nvm --help"
bash: nvm: command not found
.bashrc
มีการต่อเติม[ -z "$PS1" ] && return
โดย# If not running interactively, don't do anything
ฉันเดาว่าเป็นเหตุผลที่แม้แต่การจัดหา bashrc อย่างชัดเจนในโหมดที่ไม่โต้ตอบก็ไม่ได้ช่วยอะไร ปัญหาสามารถแก้ไขได้ด้วยการเรียกสคริปต์ด้วยตัวดำเนินการ ss64.com/bash/source.html dot . ./script.sh
แต่นั่นไม่ใช่สิ่งที่เราต้องการจดจำให้พิมพ์ทุกครั้ง
hash-variant มีหนึ่งหลุมพราง: บนบรรทัดคำสั่งคุณสามารถพิมพ์ตัวอย่างได้
one_folder/process
เพื่อให้กระบวนการทำงาน สำหรับเรื่องนี้โฟลเดอร์แม่ของ one_folder จะต้องอยู่ใน$ PATH แต่เมื่อคุณพยายามแฮชคำสั่งนี้มันจะประสบความสำเร็จเสมอ:
hash one_folder/process; echo $? # will always output '0'
$PATH
" - นี่ไม่ถูกต้องสมบูรณ์ ลองมัน. สำหรับการทำงาน, one_folder จะต้องอยู่ในไดเรกทอรีปัจจุบัน
ฉันสองใช้ "command -v" เช่นนี้
md=$(command -v mkdirhier) ; alias md=${md:=mkdir} # bash
emacs="$(command -v emacs) -nw" || emacs=nano
alias e=$emacs
[[ -z $(command -v jed) ]] && alias jed=$emacs
ฉันต้องตรวจสอบว่าติดตั้ง Git เป็นส่วนหนึ่งของการปรับใช้เซิร์ฟเวอร์CIของเราหรือไม่ สคริปต์ Bash สุดท้ายของฉันเป็นดังนี้ (เซิร์ฟเวอร์ Ubuntu):
if ! builtin type -p git &>/dev/null; then
sudo apt-get -y install git-core
fi
sudo
: หากไม่มีเงื่อนไขก็จะหยุดและขอรหัสผ่านเสมอ (เว้นแต่คุณจะทำ sudo เมื่อเร็ว ๆ นี้) BTW มันอาจมีประโยชน์ในการทำเช่นsudo -p "Type your password to install missing git-core: "
นั้นการแจ้งเตือนจะไม่ออกมาจากสีน้ำเงิน
ในการเลียนแบบ Bash type -P cmd
เราสามารถใช้ POSIX env -i type cmd 1>/dev/null 2>&1
ได้
man env
# "The option '-i' causes env to completely ignore the environment it inherits."
# In other words, there are no aliases or functions to be looked up by the type command.
ls() { echo 'Hello, world!'; }
ls
type ls
env -i type ls
cmd=ls
cmd=lsx
env -i type $cmd 1>/dev/null 2>&1 || { echo "$cmd not found"; exit 1; }
type
ดูเหมือนว่าจะเป็นbuiltin
เชลล์ส่วนใหญ่ดังนั้นจึงไม่สามารถทำงานได้เนื่องจากenv
ใช้execvp
เพื่อรันcommand
จึงcommand
ไม่สามารถเป็นได้builtin
(และbuiltin
จะทำงานในสภาพแวดล้อมเดียวกันเสมอ) นี้ล้มเหลวสำหรับฉันในbash
, ksh93
, zsh
, busybox [a]sh
และdash
ทุกที่ให้type
เป็น builtin เปลือก
หากไม่มีtype
คำสั่งภายนอกใด ๆ(ตามที่ให้ไว้ที่นี่ ) เราสามารถใช้ POSIX ได้env -i sh -c 'type cmd 1>/dev/null 2>&1'
:
# Portable version of Bash's type -P cmd (without output on stdout)
typep() {
command -p env -i PATH="$PATH" sh -c '
export LC_ALL=C LANG=C
cmd="$1"
cmd="`type "$cmd" 2>/dev/null || { echo "error: command $cmd not found; exiting ..." 1>&2; exit 1; }`"
[ $? != 0 ] && exit 1
case "$cmd" in
*\ /*) exit 0;;
*) printf "%s\n" "error: $cmd" 1>&2; exit 1;;
esac
' _ "$1" || exit 1
}
# Get your standard $PATH value
#PATH="$(command -p getconf PATH)"
typep ls
typep builtin
typep ls-temp
อย่างน้อยในMac OS X v10.6.8 (Snow Leopard) โดยใช้ทุบตี 4.2.24 (2) ไม่ตรงกับย้ายcommand -v ls
/bin/ls-temp
ในกรณีที่คุณต้องการตรวจสอบว่าโปรแกรมที่มีอยู่และเป็นจริงโปรแกรมไม่ทุบตีในตัวคำสั่งแล้วcommand
, type
และhash
ไม่เหมาะสมสำหรับการทดสอบตามที่พวกเขากลับมา 0 สถานะออกทั้งหมดในตัวคำสั่ง
ตัวอย่างเช่นมีโปรแกรมเวลาที่มีคุณสมบัติมากกว่าคำสั่งในตัวเวลา เพื่อตรวจสอบว่ามีโปรแกรมอยู่หรือไม่ฉันขอแนะนำให้ใช้which
ในตัวอย่างต่อไปนี้:
# First check if the time program exists
timeProg=`which time`
if [ "$timeProg" = "" ]
then
echo "The time program does not exist on this system."
exit 1
fi
# Invoke the time program
$timeProg --quiet -o result.txt -f "%S %U + p" du -sk ~
echo "Total CPU time: `dc -f result.txt` seconds"
rm result.txt
ฉันต้องการตอบคำถามเดียวกัน แต่ทำงานใน Makefile
install:
@if [[ ! -x "$(shell command -v ghead)" ]]; then \
echo 'ghead does not exist. Please install it.'; \
exit -1; \
fi
ต้นฉบับ
#!/bin/bash
# Commands found in the hash table are checked for existence before being
# executed and non-existence forces a normal PATH search.
shopt -s checkhash
function exists() {
local mycomm=$1; shift || return 1
hash $mycomm 2>/dev/null || \
printf "\xe2\x9c\x98 [ABRT]: $mycomm: command does not exist\n"; return 1;
}
readonly -f exists
exists notacmd
exists bash
hash
bash -c 'printf "Fin.\n"'
ผลลัพธ์
✘ [ABRT]: notacmd: command does not exist
hits command
0 /usr/bin/bash
Fin.
ฉันใช้สิ่งนี้เพราะมันง่ายมาก:
if [ `LANG=C type example 2>/dev/null|wc -l` = 1 ];then echo exists;else echo "not exists";fi
หรือ
if [ `LANG=C type example 2>/dev/null|wc -l` = 1 ];then
echo exists
else echo "not exists"
fi
มันใช้เชลล์บิวอินและสถานะก้องของโปรแกรมไปยังเอาต์พุตมาตรฐานและไม่มีข้อผิดพลาดมาตรฐาน ในทางกลับกันถ้าไม่พบคำสั่งสถานะ echos จะเป็นข้อผิดพลาดมาตรฐานเท่านั้น
which
ผลตอบแทนที่แท้จริงสำหรับสิ่งเหล่านี้type
โดยไม่มีอาร์กิวเมนต์จะส่งกลับค่าจริงสำหรับคำที่สงวนไว้และเชลล์บิลด์อิน หาก "โปรแกรม" หมายถึง "ไม่เปลี่ยนแปลงใน$PATH
" ให้ดูคำตอบนี้