ทำไมจึงควรใช้“ #! / usr / bin / env NAME” แทนที่จะเป็น“ #! / path / to / NAME” เป็น shebang ของฉัน


458

ผมสังเกตเห็นว่าบางสคริปต์ที่ฉันได้รับจากคนอื่น ๆ มี shebang #!/path/to/NAMEขณะที่คนอื่น (โดยใช้เครื่องมือเดียวกัน NAME) มี #!/usr/bin/env NAMEshebang

ทั้งคู่ดูเหมือนจะทำงานอย่างถูกต้อง ในบทช่วยสอน (บน Python) ดูเหมือนจะมีข้อเสนอแนะว่า Shebang หลังดีกว่า แต่ฉันไม่เข้าใจว่าทำไมจึงเป็นเช่นนี้

ฉันรู้ว่าเพื่อที่จะใช้ Shebang หลัง NAME จะต้องอยู่ในเส้นทางในขณะที่ Shebang แรกไม่มีข้อ จำกัด นี้

นอกจากนี้ยังปรากฏว่าสำหรับฉันคนแรกจะดีกว่า shebang เพราะมันระบุได้อย่างแม่นยำว่าที่ใดที่ NAME ตั้งอยู่ ดังนั้นในกรณีนี้หากมี NAME หลายเวอร์ชัน (เช่น / usr / bin / NAME, / usr / local / bin / NAME) กรณีแรกจะระบุว่าจะใช้อะไร

คำถามของฉันคือเหตุใด shebang แรกจึงเป็นที่ชื่นชอบของคนที่สอง



@ TheGeeko61: ในกรณีของฉันฉันมีบางสิ่งบางอย่างแตกหักและตัวแปรบางอย่างไม่ได้อยู่ใน env ดังนั้นฉันแนะนำให้ใช้ Shebang นี้เพื่อตรวจสอบว่ามีการโหลด env อย่างถูกต้องหรือไม่
Gigamegs

คำตอบ:


462

มันไม่จำเป็นต้องดีกว่า

ประโยชน์ของการ#!/usr/bin/env pythonก็คือว่ามันจะใช้สิ่งที่ปฏิบัติการปรากฏขึ้นครั้งแรกในของผู้ใช้python$PATH

ข้อเสียของ#!/usr/bin/env pythonก็คือว่ามันจะใช้สิ่งที่ปฏิบัติการปรากฏขึ้นครั้งแรกในของผู้ใช้python$PATH

นั่นหมายความว่าสคริปต์สามารถทำงานแตกต่างกันไปขึ้นอยู่กับว่าใครทำงานอยู่ สำหรับผู้ใช้หนึ่งรายอาจใช้สิ่ง/usr/bin/pythonที่ติดตั้งไว้กับระบบปฏิบัติการ อีกก็อาจจะใช้การทดลอง/home/phred/bin/pythonที่ไม่ได้ค่อนข้างทำงานอย่างถูกต้อง

และหากpythonติดตั้งเฉพาะใน/usr/local/binผู้ใช้ที่ไม่มี/usr/local/binใน$PATHจะไม่สามารถเรียกใช้สคริปต์ได้ (นั่นอาจไม่มากเกินไปสำหรับระบบที่ทันสมัย ​​แต่อาจเกิดขึ้นได้ง่ายสำหรับล่ามที่ไม่ชัดเจน)

โดยการระบุ#!/usr/bin/pythonคุณระบุว่าที่ล่ามจะใช้ในการเรียกใช้สคริปต์ในระบบโดยเฉพาะอย่างยิ่ง

ปัญหาที่อาจเกิดขึ้นอีกอย่างหนึ่งก็คือ#!/usr/bin/envกลอุบายนั้นไม่อนุญาตให้คุณส่งอาร์กิวเมนต์ไปยังผู้แปล (นอกเหนือจากชื่อของสคริปต์ซึ่งถูกส่งผ่านโดยปริยาย) ซึ่งมักจะไม่ใช่ปัญหา แต่อาจเป็นไปได้ สคริปต์ Perl จำนวนมากเขียนด้วย#!/usr/bin/perl -wแต่use warnings;แนะนำให้มาแทนที่ในวันนี้ สคริปต์ Csh ควรใช้#!/bin/csh -f- แต่ไม่แนะนำให้ใช้สคริปต์ csh ในตอนแรก แต่อาจมีตัวอย่างอื่น

ฉันมีสคริปต์ Perl จำนวนมากในระบบควบคุมแหล่งข้อมูลส่วนบุคคลที่ฉันติดตั้งเมื่อฉันตั้งค่าบัญชีในระบบใหม่ ผมใช้สคริปต์การติดตั้งที่ปรับเปลี่ยนสายของแต่ละสคริปต์ในขณะที่มันติดตั้งในของฉัน#! $HOME/bin(ฉันไม่ได้ใช้สิ่งอื่นนอกเหนือจาก#!/usr/bin/perlเมื่อเร็ว ๆ นี้มันกลับไปเวลาเมื่อ Perl มักไม่ได้ติดตั้งโดยค่าเริ่มต้น)

จุดรอง: #!/usr/bin/envเคล็ดลับคือเนื้อหาการใช้envคำสั่งที่ไม่เหมาะสมซึ่ง แต่เดิมตั้งใจไว้ (ตามชื่อหมายถึง) เพื่อเรียกใช้คำสั่งที่มีสภาพแวดล้อมที่เปลี่ยนแปลง นอกจากนี้บางระบบเก่า (รวม SunOS 4 ถ้าผมจำได้อย่างถูกต้อง) ไม่ได้มีคำสั่งในenv /usr/binสิ่งเหล่านี้ไม่น่าจะเป็นปัญหาสำคัญ envทำงานด้วยวิธีนี้สคริปต์จำนวนมากใช้#!/usr/bin/envกลอุบายและผู้ให้บริการระบบปฏิบัติการไม่น่าจะทำทุกอย่างเพื่อทำลายมัน มันอาจจะมีปัญหาถ้าคุณต้องการสคริปต์ของคุณเพื่อให้ทำงานบนระบบเก่าจริงๆ แต่คุณก็มีแนวโน้มที่จะต้องปรับเปลี่ยนมันอยู่แล้ว

อีกปัญหาที่เป็นไปได้ (ขอบคุณ Sopalajo de Arrierez สำหรับการชี้ให้เห็นในความคิดเห็น) คืองาน cron ทำงานด้วยสภาพแวดล้อมที่ถูก จำกัด โดยเฉพาะอย่างยิ่งเป็นปกติบางอย่างเช่น$PATH /usr/bin:/binดังนั้นหากไดเรกทอรีที่มีล่ามไม่ได้เกิดขึ้นในไดเรกทอรีใดไดเรกทอรีหนึ่งแม้ว่าจะเป็นค่าเริ่มต้นของคุณ$PATHในเชลล์ผู้ใช้/usr/bin/envเคล็ดลับก็จะไม่ทำงาน คุณสามารถระบุเส้นทางที่แน่นอนหรือคุณสามารถเพิ่มบรรทัดใน crontab ของคุณเพื่อตั้งค่า$PATH( man 5 crontabสำหรับรายละเอียด)


4
หาก / usr / bin / perl เป็น perl 5.8, $ HOME / bin / perl คือ 5.12 และสคริปต์ที่ต้องการ 5.12 hardcodes / usr / bin / perl ใน shebangs อาจเป็นความเจ็บปวดที่สำคัญในการเรียกใช้สคริปต์ ฉันไม่ค่อยเห็นการมี / usr / bin / env perl คว้า perl จาก PATH เป็นปัญหา แต่มักจะมีประโยชน์มาก และมันก็สวยกว่าแฮ็ค exec!
William Pursell

8
เป็นที่น่าสังเกตว่าหากคุณต้องการใช้ล่ามเฉพาะรุ่น / usr / bin / env ก็ยังดีกว่า เพียงเพราะมักจะมีล่ามหลายรุ่นติดตั้งอยู่ในเครื่องของคุณชื่อ perl5, perl5.12, perl5.10, python3.3, python3.32 เป็นต้นและหากแอปของคุณได้รับการทดสอบเฉพาะรุ่นนั้นแล้วคุณยังสามารถระบุได้ #! / usr / bin / env perl5.12 และใช้ได้แม้ว่าผู้ใช้จะทำการติดตั้งที่ใดที่หนึ่งที่ผิดปกติ จากประสบการณ์ของฉัน 'python' มักจะเป็นแค่ symlink ของเวอร์ชั่นมาตรฐานของระบบ (ไม่จำเป็นต้องเป็นเวอร์ชั่นล่าสุดของระบบ)
รูต

6
@ รูต: สำหรับ Perl use v5.12;ให้บริการบางส่วนของวัตถุประสงค์นั้น และ#!/usr/bin/env perl5.12จะล้มเหลวหากระบบมี Perl 5.14 แต่ไม่ใช่ 5.12 สำหรับ Python 2 กับ 3 #!/usr/bin/python2และ#!/usr/bin/python3น่าจะใช้ได้
Keith Thompson

3
@GoodPerson: สมมติว่าผมเขียนสคริปต์ Perl /usr/local/binจะติดตั้งใน /usr/bin/perlผมก็เพิ่งรู้ว่ามันทำงานได้อย่างถูกต้องด้วย ผมมีความคิดว่าจะทำงานร่วมกับสิ่งที่ปฏิบัติการบางอย่างของผู้ใช้สุ่มที่เกิดขึ้นที่จะมีในของเขาหรือเธอperl $PATHอาจมีบางคนกำลังทดลองใช้ Perl รุ่นโบราณบางตัว เนื่องจากฉันระบุไว้#!/usr/bin/perlสคริปต์ของฉัน (ซึ่งผู้ใช้ไม่จำเป็นต้องรู้หรือใส่ใจว่าเป็นสคริปต์ Perl) จะไม่หยุดทำงาน
Keith Thompson

5
หากไม่สามารถใช้งานได้/usr/bin/perlฉันจะค้นหาได้อย่างรวดเร็วและเป็นความรับผิดชอบของเจ้าของระบบ / ผู้ดูแลระบบที่จะทำให้มันทันสมัย หากคุณต้องการที่จะเรียกใช้สคริปต์ของฉันกับ Perl perl fooของคุณเองรู้สึกอิสระที่จะคว้าและแก้ไขสำเนาหรือเรียกได้ผ่านทาง (และคุณอาจพิจารณาถึงความเป็นไปได้ที่คน 55 คนที่ตอบคำถามนี้รู้สิ่งหนึ่งหรือสองคนมันเป็นไปได้อย่างแน่นอนว่าคุณพูดถูกและพวกเขาผิดทั้งหมด แต่นั่นไม่ใช่วิธีที่ฉันจะเดิมพัน)
Keith Thompson

101

เพราะ / usr / bin / env สามารถตีความของคุณ$PATHซึ่งทำให้สคริปต์พกพาได้มากขึ้น

#!/usr/local/bin/python

จะเรียกใช้สคริปต์ของคุณหากติดตั้ง python ใน / usr / local / bin

#!/usr/bin/env python

จะแปลความหมายของคุณ$PATHและหาหลามในไดเรกทอรีใด ๆ $PATHใน

ดังนั้นสคริปต์ของคุณเป็นแบบพกพามากขึ้นและจะทำงานโดยไม่มีการปรับเปลี่ยนในระบบที่มีการติดตั้งหลามเป็น/usr/bin/pythonหรือ/usr/local/bin/pythonหรือแม้กระทั่งไดเรกทอรีที่กำหนดเอง (ที่ได้รับการเพิ่ม$PATH) /opt/local/bin/pythonเช่น

ความสะดวกในการพกพาเป็นเหตุผลเดียวenvที่แนะนำให้ใช้กับเส้นทางฮาร์ดโค้ด


19
ไดเร็กทอรี่ที่กำหนดเองสำหรับเอ็กซีpythonคิ้วท์ทั่วไปโดยเฉพาะเมื่อvirtualenvการใช้งานเพิ่มขึ้น
Xiong Chiamiov

1
สิ่งที่เกี่ยวกับ #! pythonทำไมไม่ได้ว่าใช้งานอย่างไร
Kristianp

6
#! pythonไม่ได้ใช้เพราะคุณจะต้องอยู่ในไดเรกทอรีเดียวกับไบนารีไพ ธ อนเนื่องจากคำว่า bareword pythonถูกตีความว่าเป็นพา ธ ที่สมบูรณ์ไปยังไฟล์ bash: ./script.py: python: bad interpreter: No such file or directoryหากคุณไม่ได้มีไบนารีหลามในไดเรกทอรีปัจจุบันคุณจะได้รับข้อผิดพลาดเหมือน มันเหมือนกับว่าคุณใช้#! /not/a/real/path/python
Tim Kennedy

47

การระบุพา ธ สัมบูรณ์นั้นแม่นยำยิ่งขึ้นในระบบที่กำหนด ข้อเสียคือแม่นยำเกินไป สมมติว่าคุณรู้ว่าการติดตั้งระบบการทำงานของ Perl เก่าเกินไปสำหรับสคริปต์ของคุณและคุณต้องการใช้ของคุณเองแทน: แล้วคุณจะต้องแก้ไขสคริปต์และเปลี่ยนไป#!/usr/bin/perl #!/home/myname/bin/perlที่แย่กว่านั้นถ้าคุณมี Perl ใน/usr/binเครื่องบางเครื่อง/usr/local/binที่อื่น ๆ และ/home/myname/bin/perlในเครื่องอื่น ๆ คุณต้องเก็บสำเนาสคริปต์สามชุดแยกจากกันและเรียกใช้งานสคริปต์ที่เหมาะสมในแต่ละเครื่อง

#!/usr/bin/envแตกถ้าPATHไม่ดี แต่ก็ทำอะไรเกือบทุกอย่าง ความพยายามในการทำงานที่ไม่ดีPATHนั้นไม่ค่อยมีประโยชน์มากและบ่งชี้ว่าคุณรู้น้อยมากเกี่ยวกับระบบที่สคริปต์กำลังทำงานอยู่ดังนั้นคุณจึงไม่สามารถพึ่งพาเส้นทางที่แน่นอนได้

มีสองโปรแกรมที่มีสถานที่ที่คุณสามารถพึ่งพาในเกือบทุกยูนิกซ์ตัวแปรคือ: และ/bin/sh /usr/bin/envตัวแปร Unix ที่คลุมเครือและเกษียณอายุส่วนใหญ่มี/bin/envโดยไม่ต้องมี/usr/bin/envแต่คุณไม่น่าจะพบพวกมัน ระบบที่ทันสมัยมีความ/usr/bin/envแม่นยำเนื่องจากมีการใช้กันอย่างแพร่หลายใน shebangs /usr/bin/envเป็นสิ่งที่คุณไว้ใจได้

นอกจาก/bin/shนี้ครั้งเดียวที่คุณควรใช้เส้นทางที่แน่นอนใน Shebang คือเมื่อสคริปต์ของคุณไม่ได้หมายถึงการพกพาดังนั้นคุณจึงสามารถไว้วางใจในตำแหน่งที่ทราบสำหรับล่าม #!/bin/bashยกตัวอย่างเช่นการทุบตีสคริปต์ที่ทำงานเฉพาะบนลินุกซ์ได้อย่างปลอดภัยสามารถใช้ สคริปต์ที่มีไว้เพื่อใช้ภายในองค์กรเท่านั้นสามารถพึ่งพาข้อตกลงเกี่ยวกับตำแหน่งของล่าม

#!/usr/bin/envจะมีข้อเสีย มีความยืดหยุ่นมากกว่าการระบุเส้นทางที่แน่นอน แต่ยังต้องรู้ชื่อล่าม ในบางครั้งคุณอาจต้องการเรียกใช้ล่ามที่ไม่ได้อยู่ใน$PATHตัวอย่างเช่นในตำแหน่งที่สัมพันธ์กับสคริปต์ ในกรณีเช่นนี้คุณสามารถสร้างสคริปต์หลายภาษาที่สามารถตีความได้ทั้งโดยเชลล์มาตรฐานและโดยล่ามที่คุณต้องการ ตัวอย่างเช่นในการสร้างสคริปต์ Python 2 แบบพกพาทั้งกับระบบที่pythonเป็น Python 3 และpython2Python 2 และสำหรับระบบที่pythonเป็น Python 2 และpython2ไม่มีอยู่:

#!/bin/sh
''':'
if type python2 >/dev/null 2>/dev/null; then
  exec python2 "$0" "$@"
else
  exec python "$0" "$@"
fi
'''
# real Python script starts here
def …

22

โดยเฉพาะสำหรับ perl การใช้#!/usr/bin/envเป็นความคิดที่ดีด้วยเหตุผลสองประการ

ครั้งแรกมันไม่ได้พกพา บนแพลตฟอร์มที่ไม่ชัดเจน env ไม่ได้อยู่ใน / usr / bin ประการที่สองดังที่Keith Thompsonได้กล่าวไว้มันอาจทำให้เกิดปัญหากับการทะเลาะโต้เถียงกันในสาย shebang โซลูชั่นแบบพกพาที่สุดคือ:

#!/bin/sh
exec perl -x "$0" "$@"
#!perl

สำหรับรายละเอียดเกี่ยวกับวิธีการทำงานดู 'perldoc perlrun' และสิ่งที่พูดเกี่ยวกับอาร์กิวเมนต์ -x


anser ที่ฉันค้นหา: วิธีการเขียน porable "shebang" สำหรับสคริปต์ perl ที่จะอนุญาตให้ส่งเนื้อหาเพิ่มเติมให้กับ perl (บรรทัดสุดท้ายในตัวอย่างของคุณยอมรับ aruments เพิ่มเติม)
AmokHuginnsson

15

เหตุผลที่มีความแตกต่างระหว่างทั้งสองเป็นเพราะวิธีการดำเนินการสคริปต์

การใช้/usr/bin/env(ซึ่งตามที่กล่าวไว้ในคำตอบอื่น ๆ ไม่ได้อยู่/usr/binในระบบปฏิบัติการบางระบบ) เป็นสิ่งจำเป็นเนื่องจากคุณไม่สามารถใส่ชื่อที่สามารถใช้งานได้หลังจาก#!- มันต้องเป็นเส้นทางที่แน่นอน นี่เป็นเพราะ#!กลไกการทำงานในระดับที่ต่ำกว่าเปลือก มันเป็นส่วนหนึ่งของตัวโหลดไบนารีของเคอร์เนล สิ่งนี้สามารถทดสอบได้ วางสิ่งนี้ลงในไฟล์และทำเครื่องหมายว่าสามารถเรียกใช้งานได้:

#!bash

echo 'foo'

คุณจะพบว่ามันพิมพ์ข้อผิดพลาดเช่นนี้เมื่อคุณพยายามเรียกใช้:

Failed to execute process './test.sh'. Reason:
The file './test.sh' does not exist or could not be executed.

หากไฟล์ถูกทำเครื่องหมายว่าปฏิบัติการได้และเริ่มต้นด้วย a #!เคอร์เนล (ซึ่งไม่ทราบ$PATHหรือไดเรกทอรีปัจจุบัน: สิ่งเหล่านี้เป็นแนวคิดของผู้ใช้พื้นที่) จะค้นหาไฟล์โดยใช้พา ธ สัมบูรณ์ เพราะใช้เส้นทางที่แน่นอนเป็นปัญหา (ตามที่กล่าวไว้ในคำตอบอื่น ๆ ) บางคนขึ้นมาด้วยเคล็ดลับ: คุณสามารถเรียกใช้/usr/bin/env(ซึ่งมักจะอยู่ในสถานที่นั้น) $PATHการทำงานบางอย่างใช้


11

มีอีกสองปัญหาในการใช้ #!/usr/bin/env

  1. envมันไม่ได้แก้ปัญหาของการระบุเส้นทางแบบเต็มไปล่ามก็แค่ย้ายไปยัง

    envไม่รับประกันว่าจะได้อยู่ใน/usr/bin/envเกินกว่าที่bashจะรับประกันใน/bin/bashหรือหลาม/usr/bin/pythonมา

  2. env เขียนทับ ARGV [0] ด้วยชื่อของล่าม (e..g bash หรือ python)

    สิ่งนี้จะป้องกันชื่อสคริปต์ของคุณไม่ให้ปรากฏเช่นpsเอาท์พุท (หรือเปลี่ยนวิธีที่จะปรากฏ) และทำให้ไม่สามารถค้นหาได้ด้วยเช่นps -C scriptname.sh

[อัพเดท 2016-06-04]

และปัญหาที่สาม:

  1. การเปลี่ยนเส้นทางของคุณจะมากขึ้นการทำงานมากกว่าเพียงแค่การแก้ไขบรรทัดแรกของสคริปต์โดยเฉพาะอย่างยิ่งเมื่อมีการเขียนสคริปต์การแก้ไขดังกล่าวเป็นที่น่ารำคาญ เช่น:

    printf "%s\n" 1 i '#!'$(type -P python2) . w | ed foo.py

    การต่อท้ายหรือรอไดเรกทอรีล่วงหน้าเพื่อ $ PATH นั้นค่อนข้างง่าย (แม้ว่าคุณจะยังต้องแก้ไขไฟล์เพื่อให้ถาวร - ของคุณ~/.profileหรืออะไรก็ตาม - และมันก็ยังไกลจากสคริปต์ที่ง่ายที่จะแก้ไขเพราะเส้นทางนั้นสามารถตั้งค่าได้ทุกที่ในสคริปต์ ไม่ใช่ในบรรทัดแรก)

    การเปลี่ยนลำดับของไดเรกทอรี PATH นั้นยากกว่ามาก .... และยากกว่าการแก้ไข#!บรรทัด

    และคุณยังมีปัญหาอื่น ๆ ทั้งหมดที่ใช้#!/usr/bin/envให้

    @jlliagre แนะนำในความคิดเห็นที่#!/usr/bin/envมีประโยชน์สำหรับการทดสอบสคริปต์ของคุณด้วยล่ามหลายรุ่น "โดยการเปลี่ยนลำดับ PATH / PATH เท่านั้น"

    หากคุณต้องการทำสิ่งนั้นง่ายกว่ามากที่จะมีหลาย#!บรรทัดที่ด้านบนสุดของสคริปต์ของคุณ (พวกเขาเป็นเพียงความคิดเห็นที่ใดก็ได้ แต่บรรทัดแรก) และตัด / คัดลอกและวางที่คุณต้องการใช้ตอนนี้ บรรทัดแรก

    ในviที่จะเป็นง่ายๆเป็นย้ายเคอร์เซอร์ไปที่#!บรรทัดที่คุณต้องการแล้วพิมพ์หรือdd1GP Y1GPแม้ว่าจะมีตัวแก้ไขที่ไม่สำคัญเหมือนnanoกัน แต่ก็ใช้เวลาไม่กี่วินาทีในการใช้เมาส์เพื่อคัดลอกและวาง


โดยรวมแล้วข้อดีของการใช้#!/usr/bin/envมีน้อยที่สุดและแน่นอนไม่ได้ใกล้เคียงกับข้อเสียที่มีมากกว่า แม้แต่ข้อได้เปรียบ "ความสะดวกสบาย" ก็เป็นสิ่งหลอกลวง

IMO เป็นความคิดที่ไม่ดีที่ได้รับการสนับสนุนจากโปรแกรมเมอร์บางประเภทที่คิดว่าระบบปฏิบัติการไม่ใช่สิ่งที่จะทำงานร่วมกับพวกเขา แต่เป็นปัญหาที่ต้องแก้ไข

PS: นี่เป็นสคริปต์ง่าย ๆ ในการเปลี่ยนล่ามของหลายไฟล์พร้อมกัน

change-shebang.sh:

#!/bin/bash

interpreter="$1"
shift

if [ -z "$(type -P $interpreter)" ] ; then
  echo "Error: '$interpreter' is not executable." >&2
  exit 1
fi

if [ ! -d "$interpreter" ] && [ -x "$interpreter" ] ; then
  shebang='#!'"$(realpath -e $interpreter)" || exit 1
else
  shebang='#!'"$(type -P $interpreter)"
fi

for f in "$@" ; do
  printf "%s\n" 1 i "$shebang" . w | ed "$f"
done

เรียกใช้เป็นเช่นchange-shebang.sh python2.7 *.pyหรือchange-shebang.sh $HOME/bin/my-experimental-ruby *.rb


4
ไม่มีใครที่นี่พูดถึงปัญหา ARGV [0] และไม่มีใครพูดถึงปัญหา / path / to / env ในรูปแบบที่กล่าวถึงข้อโต้แย้งข้อใดข้อหนึ่งในการใช้โดยตรง (เช่น bash หรือ perl อาจอยู่ในตำแหน่งที่ไม่คาดคิด)
cas

2
ปัญหาเส้นทางล่ามได้รับการแก้ไขอย่างง่ายดายโดยดูแลระบบที่มี symlink หรือโดยผู้ใช้แก้ไขสคริปต์ของพวกเขา แน่นอนว่ามันไม่ใช่ปัญหาที่สำคัญพอที่จะกระตุ้นให้ผู้คนหยิบยกประเด็นอื่น ๆ ทั้งหมดที่เกิดขึ้นจากการใช้ env ในบรรทัด Shebang ที่กล่าวถึงที่นี่และคำถามอื่น ๆ การส่งเสริมโซลูชันที่ไม่ดีในลักษณะเดียวกันกับที่ส่งเสริมการcshเขียนสคริปต์คือการส่งเสริมโซลูชันที่ไม่ดี: เป็นงานที่มีประโยชน์ แต่มีทางเลือกที่ดีกว่ามาก
cas

3
ผู้ดูแลระบบสามารถขอให้ดูแลระบบของพวกเขาที่จะทำมัน หรือพวกเขาสามารถแก้ไขสคริปต์และเปลี่ยน#!บรรทัด
cas

2
นั่นคือสิ่งที่ env ช่วยหลีกเลี่ยง: ขึ้นอยู่กับ sysadmin หรือ OS ความรู้ด้านเทคนิคเฉพาะที่ไม่เกี่ยวข้องกับหลามหรืออะไรก็ตาม
jlliagre

1
ฉันหวังว่าฉันสามารถโหวตได้เป็นพันครั้งเพราะจริง ๆ แล้วมันเป็นคำตอบที่ดีไม่ว่าจะด้วยวิธีใด - ถ้ามีคนใช้/usr/bin/envและฉันต้องกำจัดมันในพื้นที่หรือถ้าพวกเขาไม่ได้ใช้มันและฉันต้องเพิ่มมัน ทั้งสองกรณีสามารถเกิดขึ้นได้ดังนั้นสคริปต์ที่ให้ไว้ในคำตอบนี้เป็นเครื่องมือที่มีประโยชน์ที่อาจมีในกล่องเครื่องมือ
jstine

8

เพิ่มอีกตัวอย่างที่นี่:

การใช้envยังมีประโยชน์เมื่อคุณต้องการแชร์สคริปต์ระหว่างหลาย ๆrvmสภาพแวดล้อม

การรันสิ่งนี้บนบรรทัด cmd แสดงเวอร์ชัน ruby ​​ที่จะใช้เมื่อ #!/usr/bin/env rubyใช้ภายในสคริปต์:

env ruby --version

ดังนั้นเมื่อคุณใช้envคุณสามารถใช้ ruby ​​version ต่าง ๆ ผ่าน rvm โดยไม่ต้องเปลี่ยนสคริปต์ของคุณ


1
//, ความคิดที่ยอดเยี่ยม จุดรวมของล่ามหลายไม่ได้ที่จะทำลายรหัสหรือมีรหัสขึ้นอยู่กับว่า เฉพาะ ล่าม
นาธาน Basanese

4

หากคุณเขียนอย่างเดียวเพื่อตัวคุณเองหรือเพื่องานของคุณและที่ตั้งของล่ามที่คุณโทรหาอยู่ในสถานที่เดียวกันเสมอโดยทั้งหมดใช้เส้นทางตรง ในกรณีอื่น ๆ #!/usr/bin/envทุกคนใช้

นี่คือเหตุผล: ในสถานการณ์ของคุณpythonล่ามอยู่ในสถานที่เดียวกันโดยไม่คำนึงถึงไวยากรณ์ที่คุณใช้ แต่สำหรับหลาย ๆ คนอาจมีการติดตั้งในที่อื่น แต่ส่วนใหญ่ล่ามการเขียนโปรแกรมที่สำคัญมีอยู่ในจำนวนมากของซอฟต์แวร์ใหม่จะผิดนัด/usr/bin//usr/local/bin/

ฉันจะเถียงว่าจะใช้เสมอ#!/usr/bin/envเพราะถ้าคุณมีล่ามเดียวกันหลายรุ่นติดตั้งไว้และคุณไม่รู้ว่าเชลล์ของคุณจะเป็นค่าเริ่มต้นคุณควรแก้ไขมัน


5
"ในกรณีอื่น ๆ ให้ใช้ #! / usr / bin / env" แรงเกินไป // เป็น @KeithThompson และคนอื่น ๆ ชี้ให้เห็น #! / usr / bin / env หมายความว่าสคริปต์สามารถทำงานแตกต่างกันไปขึ้นอยู่กับว่าใครทำงานอย่างไร บางครั้งพฤติกรรมที่แตกต่างนี้อาจเป็นข้อผิดพลาดด้านความปลอดภัย // ตัวอย่างเช่นห้ามใช้ "#! / usr / bin / env python" สำหรับสคริปต์ setuid หรือ setgid เนื่องจากผู้ใช้ที่เรียกใช้สคริปต์สามารถวางมัลแวร์ไว้ในไฟล์ชื่อ "python" ใน PATH ไม่ว่าสคริปต์ setuid / gid จะเป็นความคิดที่ดีหรือไม่ แต่เป็นเรื่องที่แน่นอนไม่มีการดำเนินการ setuid / gid ควรเชื่อถือได้กับสภาพแวดล้อมที่ผู้ใช้จัดหา
Krazy Glew

@KrazyGlew คุณไม่สามารถตั้งค่าสคริปต์บน Linux คุณทำโปรแกรมปฏิบัติการได้ และเมื่อเขียนไฟล์เรียกทำงานนี้เป็นแนวปฏิบัติที่ดีและทำกันอย่างแพร่หลายเพื่อล้างตัวแปรสภาพแวดล้อม ตัวแปรสภาพแวดล้อมบางตัวยังถูกละเว้นไปด้วย
MayeulC

3

เพื่อเหตุผลในการพกพาและใช้งานร่วมกันได้ดีกว่าการใช้งาน

#!/usr/bin/env bash

แทน

#!/usr/bin/bash

มีความเป็นไปได้มากมายที่ไบนารีอาจตั้งอยู่บนระบบ Linux / Unix ตรวจสอบ manpage (7) สำหรับคำอธิบายโดยละเอียดของลำดับชั้นของระบบไฟล์

FreeBSD เช่นการติดตั้งซอฟแวร์ทั้งหมดซึ่งไม่ได้เป็นส่วนหนึ่งของระบบฐานใน/ usr / local / ตั้งแต่ทุบตีไม่ได้เป็นส่วนหนึ่งของระบบฐานไบนารีทุบตีมีการติดตั้งที่/ usr / local / bin / ทุบตี

เมื่อคุณต้องการทุบตี / csh / Perl / สิ่งสคริปต์แบบพกพาซึ่งทำงานภายใต้การกระจายมากที่สุด Linux และ FreeBSD คุณควรใช้#! / usr / bin / env

โปรดทราบด้วยว่าการติดตั้งลีนุกซ์ส่วนใหญ่มีการเชื่อมโยง (ฮาร์ด) env ไบนารี่กับ / bin / env หรือ softlinked / usr / bin ไปยัง / bin ซึ่งไม่ควรใช้ใน shebang จึงไม่ใช้#! / bin / env

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