ทำความเข้าใจกับคำสั่ง shell builtin


12

ในคู่มือทุบตีมันเขียนไว้ว่า

Builtin commands are contained >>> within <<< the shell itself

นอกจากนี้คำตอบนี้ระบุว่า

A built-in command is simply a command that the shell carries out itself,
instead of interpreting it as a request to load and run some
>>> other program <<<

เมื่อผมทำงานcompgen -bเกี่ยวกับbash 4.4ผมได้รับรายชื่อของเปลือกทั้งหมดในตัวคำสั่ง ฉันเห็นตัวอย่างนั้น[และkillถูกระบุว่าเป็นเชลล์บิวด์อิน แต่สถานที่จริงของพวกเขาคือ:

/usr/bin/[
/bin/kill

ฉันคิดว่าเป็นbuiltinวิธีที่คำสั่งจะถูกรวบรวมเป็น/bin/bashปฏิบัติการ ดังนั้นสิ่งที่ทำให้ฉันสับสนจริงๆ: โปรดแก้ไขฉัน แต่คำสั่งแยกต่างหากจะเป็นbuiltinอย่างไรได้อย่างไรเมื่อมันไม่ได้เป็นส่วนหนึ่งของเชลล์?


1
บางคำสั่งเดิมมีอยู่เป็นยูทิลิตี้แยก สถานะของพวกเขาตอนนี้เป็นไปตามมาตรฐาน POSIX พกพาเช่นเดียวกับความเข้ากันได้ย้อนหลัง Shell ใช้บางอย่างในตัวเพื่อประสิทธิภาพ อาจมีเหตุผลอื่น แต่นั่นเกี่ยวกับมันโดยไม่มีรายละเอียดมากเกินไป
Sergiy Kolodyazhnyy

1
อีกเหตุผลที่ฉันคิดว่าเป็นเพราะบางคำสั่งในตัวมีความจำเป็นสำหรับเชลล์โดยเฉพาะเช่นexecจัดการไฟล์ descriptors และeval การประเมินคำสั่ง พวกเขาไม่จำเป็นต้องใช้คำสั่งแบบสแตนด์อโลน
Sergiy Kolodyazhnyy

คำตอบ:


16

คำสั่งที่สร้างไว้ในเชลล์มักจะถูกสร้างขึ้นเนื่องจากการเพิ่มประสิทธิภาพที่สิ่งนี้ให้ เรียกภายนอก ตัวอย่างเช่นจะช้ากว่าที่ใช้ในการสร้างprintfprintf

เนื่องจากยูทิลิตี้บางอย่างไม่จำเป็นต้องมีการสร้างขึ้นภายในนอกจากจะมีความพิเศษเช่นcdพวกเขายังมีให้เป็นสาธารณูปโภคภายนอก นี่คือสคริปต์ที่จะไม่ทำลายหากพวกเขาถูกตีความโดยเชลล์ที่ไม่ได้ให้ตัวในการเทียบเท่า

บิวด์อินบางเชลล์ยังจัดเตรียมส่วนขยายให้กับคำสั่งเทียบเท่าภายนอก printfตัวอย่างเช่นBash's สามารถทำได้

$ printf -v message 'Hello %s' "world"
$ echo "$message"
Hello world

(พิมพ์ไปที่ตัวแปร) ซึ่งภายนอก/usr/bin/printfไม่สามารถทำได้เนื่องจากไม่สามารถเข้าถึงตัวแปรเชลล์ในเซสชันเชลล์ปัจจุบัน (และไม่สามารถเปลี่ยนแปลงได้)

สร้างขึ้นในระบบสาธารณูปโภคยังไม่ได้มีข้อ จำกัด ที่บรรทัดคำสั่งของพวกเขาขยายตัวจะต้องมีสั้นกว่าความยาวบาง การทำ

printf '%s\n' *

จึงปลอดภัยหากprintfเป็นคำสั่งในตัวเชลล์ ข้อ จำกัด เกี่ยวกับความยาวของบรรทัดคำสั่งมาจากexecve()ฟังก์ชันไลบรารี C ที่ใช้เพื่อดำเนินการคำสั่งภายนอก หากบรรทัดคำสั่งและสภาพแวดล้อมปัจจุบันมีขนาดใหญ่กว่าARG_MAXไบต์ (ดูgetconf ARG_MAXในเชลล์) การเรียกใช้execve()จะล้มเหลว หากยูทิลิตี้ถูกสร้างขึ้นในเชลล์คุณexecve()ไม่จำเป็นต้องเรียกใช้

$PATHสร้างขึ้นในสาธารณูปโภคจะมีความสำคัญมากกว่าที่พบในสาธารณูปโภค หากต้องการปิดใช้งานคำสั่งในตัวbashให้ใช้เช่น

enable -n printf

มีรายการย่อของยูทิลิตี้ที่จำเป็นต้องสร้างไว้ในเชลล์ (นำมาจากรายการบิวด์อินพิเศษของ POSIX มาตรฐาน)

break
colon (:)
continue
dot (.)
eval
exec
exit
export
readonly
return
set
shift
times
trap
unset

สิ่งเหล่านี้จำเป็นต้องถูกสร้างขึ้นภายในเนื่องจากพวกเขาจัดการสภาพแวดล้อมและการไหลของโปรแกรมของเชลล์เซสชันปัจจุบันโดยตรง ยูทิลิตีภายนอกจะไม่สามารถทำได้

ที่น่าสนใจcdไม่ได้เป็นส่วนหนึ่งของรายการนี้ แต่ POSIX พูดเกี่ยวกับสิ่งต่อไปนี้ :

เนื่องจากcdส่งผลกระทบต่อสภาพแวดล้อมการเรียกใช้เชลล์ในปัจจุบันจึงมีการจัดเตรียมไว้เป็นเชลล์ปกติในตัว ถ้ามันถูกเรียกใน subshell หรือสภาพแวดล้อมการดำเนินการยูทิลิตี้ที่แยกต่างหากเช่นหนึ่งในสิ่งต่อไปนี้:

(cd /tmp)
nohup cd
find . -exec cd {} \;

ไม่ส่งผลกระทบต่อไดเร็กทอรีการทำงานของสภาพแวดล้อมของผู้โทร

ฉันจึงสมมติว่าตัว "พิเศษ" ไม่สามารถมีคู่หูภายนอกได้ในขณะที่cdในทางทฤษฎีอาจมี (แต่ก็ไม่ได้ทำอะไรมาก)


IIRC chdir/ cdเป็นไบนารีภายนอกในช่วงต้นของ Unices / pre-Unix ก่อนหน้าforkนี้
Xophmeister

@Xophmeister Solaris 11.4 (เบต้า) ยังคงมีอยู่/usr/bin/cdแต่จะไม่เปลี่ยนไดเรกทอรีการทำงานปัจจุบัน คู่มือบอกว่า: /usr/bin/cdไม่มีผลต่อกระบวนการเรียกใช้ แต่สามารถใช้เพื่อกำหนดว่าไดเรกทอรีที่กำหนดสามารถตั้งเป็นไดเรกทอรีปัจจุบันได้หรือไม่
Kusalananda

2
อีกเหตุผลที่เฉพาะเจาะจงสำหรับบิวอิน: บิวอินkillก็ดีเพราะมันไม่จำเป็นต้องแยกกระบวนการอื่นให้ดีถ้าคุณมีจำนวน จำกัด กระบวนการ
Derobert

7

คุณ (สับสนมาก) สับสนเนื่องจากข้อเท็จจริงว่ามีบางบิลด์อยู่ทั้งเป็นบิลด์และคำสั่งภายนอก ดังนั้นในขณะที่คุณพูดถูกมีตัวอย่างเช่นมี/bin/[คำสั่งซึ่งไม่ได้หมายความว่า "ตำแหน่งจริง" ของมันอยู่ใน/binนั้น

วิธีง่ายๆในการทดสอบสิ่งนี้คือการรันtypeด้วย-aสวิตช์ซึ่งจะแสดงอินสแตนซ์ทั้งหมดของคำสั่ง ในระบบ Arch ของฉันนั่นแสดงให้เห็นว่า:

$ type -a [
[ is a shell builtin
[ is /sbin/[
[ is /usr/sbin/[
[ is /usr/bin/[

โปรดทราบว่า/sbin, /usr/sbinและ/binมี symlinks ทั้งหมดชี้ไป/usr/binจึงมีเพียงหนึ่งภายนอก[:

$ readlink -f /usr/sbin /sbin /bin/
/usr/bin
/usr/bin
/usr/bin

อย่างที่คุณเห็น[เป็นทั้งบิลด์อินและคำสั่งภายนอกและเหมือนกันกับเชลล์บิลด์อินอื่น ๆ อย่างไรก็ตามนั่นไม่ได้เปลี่ยนความจริงที่ว่าพวกมันเป็นเชลล์บิลด์อินด้วยเช่นกันคอมไพล์ลงในเชลล์เอง


ทำไม distro ให้คำสั่งภายนอกแยกต่างหากสำหรับคำสั่งภายในที่มีอยู่แล้ว? ทำไมพวกเขาซ้ำกัน
LoveWithMaths

1
@linuxuser ยูทิลิตี้เหล่านี้บางอย่างจำเป็นต้องใช้โดย POSIX และคุณไม่สามารถรู้ได้ว่าเชลล์ที่ผู้ใช้กำลังใช้งานอยู่หรือไม่ อย่าคิดว่าพวกเขาเป็นคำสั่งภายในของระบบปฏิบัติการพวกเขาเป็นเพียงคำสั่งภายในของเชลล์และเชลล์สามารถเปลี่ยนได้
terdon

ฉันมีข้อสงสัย 1 ตอนนี้หากคำสั่งภายในจัดทำโดยเชลล์ แล้วใครเป็นผู้ให้คำสั่งภายนอก เช่นฉันได้สังเกตคำสั่งมากมายที่มีทั้งภายในและภายนอกคำสั่ง แต่ฉันติดตั้งพวกเขาอย่างชัดเจน; ดังนั้นใครเป็นผู้ให้คำสั่งจากภายนอก? Distro ให้ข้อมูลถูกต้องหรือไม่
LoveWithMaths

@linuxuser ขึ้นอยู่กับคำสั่งและระบบปฏิบัติการ ตัวอย่างเช่นใน Arch Linux ของฉัน/bin/printfมีการติดตั้งโดยcoreutilsแพคเกจและโดย/bin/kill util-linux
terdon

ฉันขอโทษ แต่ฉันก็ยังไม่ชัดเจนซึ่งจาก distro ให้มา? และสิ่งที่เกี่ยวกับอีกอันซึ่งไม่ได้จัดไว้ให้โดย distro ดังนั้นใครเป็นผู้จัดหาให้
LoveWithMaths
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.