ทำไมโปรแกรมของฉันถูกเรียกว่า "set" ไม่ถูกเรียกใช้งาน?


10

ฉันได้สร้างโปรแกรม C อย่างง่ายเช่นนั้น:

int main(int argc, char *argv[]) {

    if (argc != 5) {
       fputs("Not enough arguments!\n", stderr);
       exit(EXIT_FAILURE);
    }

และฉันมีเส้นทางของฉันแก้ไขในetc / bash.bashrcเช่นนั้น

PATH=.:$PATH

ฉันได้บันทึกโปรแกรมนี้เป็น set.c และกำลังรวบรวมด้วย

gcc -o set set.c

ในโฟลเดอร์

~/Programming/so

อย่างไรก็ตามเมื่อฉันโทร

set 2 3

ไม่มีอะไรเกิดขึ้น. ไม่มีข้อความที่ปรากฏ

การเรียกร้อง

./set 2 3

ให้ผลลัพธ์ที่คาดหวัง

ฉันไม่เคยมีปัญหากับ PATH มาก่อนและ

which set

./setผลตอบแทน ดังนั้นดูเหมือนว่า PATH จะเป็นสิ่งที่ถูกต้อง เกิดอะไรขึ้น


10
มันค่อนข้างอันตรายที่จะเพิ่ม '.' เส้นทางของคุณ ดีกว่าที่จะใช้. / เมื่อเรียกใช้งานบางอย่างจากโลคัลไดเร็กทอรีหรือย้ายไฟล์ปฏิบัติการไปยังไดเร็กทอรีที่รู้จักกันดีเช่น ~ / bin /
TREE

7
มันเป็นความคิดที่ดีที่จะเรียกโปรแกรมการทดสอบของคุณtestด้วยเหตุผลเดียวกัน testเป็นเปลือกในตัวด้วย
Jonathan Leffler

@JanathanLeffler แต่สำหรับการทดสอบอย่างรวดเร็วเรียกโปรแกรมtestดูเหมือนว่าเหมาะสม แน่นอนตามเวลาที่คุณใส่ไว้ในของPATHคุณคุณควรจะเกิดขึ้นกับชื่อที่แตกต่างกัน และจนกว่าคุณจะวางโปรแกรมในของPATHคุณคุณจะต้องเรียกมันว่า./testต่อไป ดังนั้นมันก็โอเคที่จะใช้ชื่อtestของโปรแกรมตราบใดที่เป็นการทดสอบอย่างรวดเร็วซึ่งคุณตั้งใจจะลบก่อนสิ้นวัน
kasperd

1
@kasperd: fooเท่าที่ผมทราบชื่อธรรมดาสำหรับโปรแกรมการทดสอบอย่างรวดเร็วคือ
hmakholm ออกเดินทางจากโมนิก้า

หากคุณตั้งชื่อlsแล้วเมื่อใดก็ตามที่คุณไปเพื่อดูว่ามีอยู่มันจะทำงาน (แต่ถ้าคุณปรับเปลี่ยนเส้นทางของคุณตามที่คุณทำในคำถาม)
ctrl-alt-delor

คำตอบ:


24

แทนที่จะใช้whichซึ่งไม่ทำงานเมื่อคุณต้องการมากที่สุดใช้typeเพื่อกำหนดสิ่งที่จะทำงานเมื่อคุณพิมพ์คำสั่ง:

$ which set
./set
$ type set
set is a shell builtin

เชลล์จะค้นหาบิวด์อินเสมอก่อนค้นหา$PATHดังนั้นการตั้งค่า$PATHจะไม่ช่วยที่นี่

เป็นการดีที่สุดที่จะเปลี่ยนชื่อไฟล์ที่เรียกใช้งานของคุณเป็นอย่างอื่น แต่ถ้าการมอบหมายของคุณต้องการโปรแกรมที่มีชื่อsetคุณสามารถใช้ฟังก์ชันเชลล์ได้:

$ function set { ./set; }
$ type set
set is a function
set ()
{
    ./set
}

(ใช้งานได้bashแต่เชลล์อื่น ๆ เช่นkshอาจไม่อนุญาตดูคำตอบของ mikeserv สำหรับโซลูชันแบบพกพาที่มากขึ้น)

ตอนนี้พิมพ์setจะทำงานฟังก์ชั่นที่มีชื่อว่า "ชุด" ./setซึ่งรัน GNU bashมีลักษณะการทำงานก่อนที่จะมองหา builtins และจะมองหา builtins $PATHก่อนที่จะค้นหา ส่วนชื่อ "คำสั่งปฏิบัติการ" ในหน้า bash man ให้ข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้

ดูเพิ่มเติมเอกสารบนbuiltinและcommand: และhelp builtinhelp command


3
คุณแนะนำtypeมากกว่าwhichแต่อย่าให้เหตุผลอะไรเลย ( ฉันรู้ว่าทำไมแต่คนที่ต้องการคำแนะนำจะไม่.)
CJM

1
@cjm ต่อไปนี้เป็นบทความทั้งหมดเกี่ยวกับสาเหตุที่ไม่ : unix.stackexchange.com/questions/85249/…
Anthony Geoghegan

ข้อมูลมาก คุณไม่เคยคาดเดาว่าจะมีการโต้เถียงกันมากกับคำสั่งง่ายๆที่ดูเหมือนจะเป็นงานง่าย
Ganea Dan Andrei

4
@GaneaDanAndrei เป็นหลักใช้typeแทนwhichไม่ได้ตั้งชื่อโปรแกรมของคุณ "ตั้ง" และตระหนักว่าfunction set { ./set; }แฮ็คที่น่าเกลียดที่คุณควรหลีกเลี่ยง
yellowantphil

11

setเป็น builtin ใน bash (และอาจเป็น shell อื่น ๆ ) ซึ่งหมายความว่า bash จะไม่แม้แต่ค้นหาเส้นทางเมื่อค้นหาฟังก์ชัน

ในฐานะที่เป็นคำพูดด้านข้างฉันขอแนะนำอย่างยิ่งให้ต่อต้านการเพิ่ม.เส้นทางเพื่อเหตุผลด้านความปลอดภัย ลองนึกภาพตัวอย่างcdไอเอ็นจีออกจาก/tmpหลังจากที่ผู้ใช้อื่น ๆ /tmp/cdเพิ่มแฟ้มที่ปฏิบัติการ


2
ใช่มันเป็นความคิดงี่เง่าที่ครูของฉันบังคับให้เราเพื่อที่จะไม่ดูไม่เป็นมืออาชีพในขณะที่นำเสนอโปรแกรม "เขาคะแนนคุณลงถ้ามันไม่ได้ทำ
Ganea Dan Andrei

1
Brownie ให้คะแนนอาจารย์ที่ดี :(
klimpergeist

4
cdsetเป็นเปลือกในตัวดังนั้นตัวอย่างจะไม่ทำงานด้วยเหตุผลเดียวกันเช่นเดียวกับ
Emil Jeřábek

15
การใช้./fooเพื่อเรียกใช้โปรแกรมเป็นมืออาชีพ มันแสดงให้เห็นว่าคุณเข้าใจว่าทำไม.ไม่ควรอยู่ใน $ PATH ครูของคุณผิดและคุณอาจบอกเขาว่าฉันพูดอย่างนั้น
zwol

10

setไม่ได้เป็นเพียงแค่ในตัวมันเป็นbuiltin พิเศษ POSIX มีคำสั่งในตัวไม่กี่ตัวที่ระบุมาตรฐานที่จะพบในการค้นหาคำสั่งก่อนสิ่งอื่น - $PATHไม่ได้ค้นหาชื่อฟังก์ชั่นจะไม่ถูกค้นหาและอื่น ๆ บิวอินส่วนใหญ่ที่ไม่ได้ พิเศษเป็นสิ่งจำเป็นโดยมาตรฐาน POSIX ที่พบในของคุณ$PATH ก่อนที่เชลล์จะรันโพรซีเดอร์บิวด์อินของตัวเอง นี่คือความจริงของechoและอื่น ๆ ส่วนใหญ่( แต่ไม่ว่าจะเป็นมาตรฐานได้รับเกียรติในส่วนนี้เป็นเรื่องของการต่อสู้ที่กลุ่มที่เปิดรายชื่อผู้รับจดหมายในอดีต)แต่ไม่ได้ของset, trap, break,return, continue, ., :, times, eval, exit, export, readonly, หรือunsetexec

ทั้งหมดเหล่านี้เป็นชื่อที่สงวนไว้ของเชลล์และพวกเขามีคุณสมบัติพิเศษนอกเหนือจากลำดับการตั้งค่าสำหรับการค้นหาคำสั่งเช่นกัน ตัวอย่างเช่นคุณไม่สามารถกำหนดฟังก์ชันเชลล์ด้วยชื่อใด ๆ เหล่านั้นในเชลล์ที่สอดคล้องกับมาตรฐาน นี่คือสิ่งที่ดี - มันช่วยให้คนเขียนสคริปต์แบบพกพาได้อย่างปลอดภัย เหล่านี้คือคำสั่งพื้นฐานที่ผู้เขียนสคริปต์ที่มีประสบการณ์สามารถสร้างรากฐานที่ปลอดภัยและเชื่อถือได้ในสภาพแวดล้อมของเขาหรือเธอ การบุกรุกเนมสเปซนี้ไม่แนะนำให้เลือก

aliasแต่ถ้าคุณไม่ต้องการที่จะบุกมันคุณสามารถทำได้ด้วย portably ลำดับการขยายตัวของเชลล์ช่วยให้สามารถแก้ไขปัญหานี้ได้ เนื่องจากaliasคำสั่งขยายในขณะที่คำสั่งกำลังอ่านสิ่งใดก็ตามที่คุณแทนที่setชื่อด้วยในคำจำกัดความของคุณจะขยายอย่างถูกต้องจึงอาจไม่ควรขยายเป็นชื่อใดชื่อหนึ่ง

ดังนั้นคุณสามารถทำได้:

alias set=./set

... ซึ่งจะทำงานได้ดี


3

ปัญหาคือว่าsetshell builtin และทางออกที่ดีที่สุดคือการใช้ชื่ออื่นสำหรับโปรแกรมปฏิบัติการของคุณ

เมื่อสัปดาห์ที่แล้วฉันถามคำถามเกี่ยวกับวิธีเรียกใช้คำสั่งระบบแทนเชลล์บิลด์อินที่มีชื่อเดียวกันและวิธีแก้ปัญหาที่ฉันยอมรับคือการเรียกใช้คำสั่งผ่านenv:

env set 2 3

สำหรับกรณีนี้โดยเฉพาะที่คุณรู้อยู่แล้วว่าคำสั่งที่คุณต้องการใช้นั้นอยู่ในไดเรกทอรีปัจจุบันของคุณมันจะดีกว่าถ้าคุณรันไฟล์ปฏิบัติการโดยตรงโดยการป้อนพา ธ ของมัน (ใช้.เพื่อเป็นตัวแทนไดเรกทอรีทำงานปัจจุบัน):

./set 2 3

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

คำแนะนำเช่นการใช้commandbuiltin จะไม่ทำงานใน Bash: สิ่งนี้จะป้องกันไม่ให้ฟังก์ชันเชลล์ทำงานเท่านั้น ในขณะที่ยังไม่มีการจัดทำเอกสารฉันยังสังเกตเห็นว่าการใช้commandยังระงับคำหลักของเชลล์ด้วย แต่ก็จะไม่ทำเช่นเดียวกันสำหรับเปลือกbuiltinssetเช่น ตามที่ฉันเข้าใจแล้วมันcommandอาจทำงานกับเชลล์อื่น ๆ เช่น zsh

นอกจากนี้เทคนิคเช่น\setหรือ"set"หรือ'set'ไม่ทำงานสำหรับ builtins ทุบตี - แม้ว่าพวกเขาจะมีประโยชน์สำหรับการเรียกใช้ไฟล์ปฏิบัติการแทนนามแฝงหรือเปลือกคำหลัก

หมายเหตุ: คำตอบนี้เริ่มแรกเป็นความคิดเห็นในคำตอบของ Eric (ยอมรับ) แต่ขยายใหญ่เกินไปที่จะแสดงความคิดเห็น คำตอบอื่น ๆ ที่แนะนำให้ใช้typeและไม่เพิ่ม.ใน PATH นั้นเป็นคำตอบที่ดี

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