เพื่อ env หรือไม่ที่จะ env


32

ความแตกต่างระหว่างคำสั่งคืออะไร

$ env FOO=bar baz

และ

$ FOO=bar baz

มีผลกระทบอะไรenvบ้าง


4
เรียงลำดับของคำถามด้านข้าง แต่คุณลักษณะนั้นเรียกว่าอะไรเมื่อคุณตั้งค่าตัวแปรสภาพแวดล้อมสำหรับคำสั่งย่อยเดียวเช่นนั้น ฉันมักจะมีเวลาหาข้อมูลเกี่ยวกับเรื่องนี้เพราะฉันไม่รู้ว่ามันคืออะไร
John Cromartie

1
@ JohnCromartie คุณควรถามว่าเป็นคำถาม
cjm

1
สำหรับ bash มีการบันทึกไว้ที่นี่: gnu.org/software/bash/manual/…
glenn jackman

2
@JohnCromartie มันเป็นส่วนประกอบที่เป็นตัวเลือกของทุกคำสั่งเชลล์ดังนั้นมันจึงอยู่ในส่วน "คำสั่งอย่างง่าย" ของคู่มือเชลล์ส่วนใหญ่ สำหรับ POSIX ที่จะเป็นที่นี่ Glenn เชื่อมโยงส่วนที่คล้ายคลึงกันจากคู่มือทุบตีสำหรับคุณแล้ว
jw013

การตั้งค่าตัวแปรที่ไม่มีอยู่ผ่านการกำหนดจะสร้างตัวแปรเชลล์ การตั้งค่าผ่าน ENV หรือการส่งออกตัวแปรจะผลักดันตัวแปรไปยังสภาพแวดล้อมการทำงานของเชลล์ การเปลี่ยนค่าของตัวแปรที่มีอยู่จะอัปเดตค่าสภาพแวดล้อมการดำเนินการหากมีอยู่มิฉะนั้นเปลี่ยนแปลงในตัวแปรภายในของเชลล์
Johan

คำตอบ:


26

พวกมันมีหน้าที่เทียบเท่า

แตกต่างที่สำคัญคือการที่env FOO=bar bazเกี่ยวข้องกับการเรียกกระบวนการตัวกลางระหว่างเปลือกและbazที่เช่นเดียวกับเปลือกจะเรียกโดยตรงFOO=bar baz ดังนั้นในเรื่องที่เป็นที่ต้องการbaz
FOO=bar baz

สถานการณ์เดียวที่ฉันพบว่าตัวเองกำลังใช้env FOO=barอยู่คือที่ฉันต้องส่งคำสั่งไปยังคำสั่งอื่น
เป็นตัวอย่างเฉพาะสมมติว่าฉันมีสคริปต์ตัวตัดคำที่ทำการแก้ไขบางอย่างของสภาพแวดล้อมและจากนั้นเรียกexecใช้คำสั่งที่ส่งผ่านไปเช่น:

#!/bin/bash
FOO=bob
some stuff
exec "$@"

หากคุณดำเนินการตามmyscript FOO=bar bazนั้นexecจะทำให้เกิดข้อผิดพลาดตามที่exec FOO=bar bazไม่ถูกต้อง
แต่คุณเรียกมันว่าmyscript env FOO=bar bazสิ่งที่ถูกดำเนินการexec env FOO=bar bazและมีผลสมบูรณ์


1
คุณสามารถทำได้FOO=bar exec bazดังนั้นคุณไม่จำเป็นต้องenvอยู่ในจุดสุดท้าย
Stéphane Chazelas

เมื่อคุณทำexecบางสิ่งมันใช้สภาพแวดล้อมปัจจุบันของคุณหรือไม่?
เกล็นแจ็

1
@StephaneChazelas Ditto และคุณยังสามารถที่จะผ่านตัวแปรสภาพแวดล้อมโดยไม่จำเป็นต้องสำหรับsudo FOO=bar baz env
Mike Miller

1
@StephaneChazelas ใช้งานได้เฉพาะในกรณีที่ฉันต้องการใส่FOO=barสคริปต์ หากFOOไม่เสมอbarไปฉันไม่ต้องการเขียนโค้ดอย่างหนักและส่งผ่านแทน
Patrick

@glennjackman ใช่มันไม่ได้นานเท่าที่ตัวแปรจะถูกส่งออกหรือผ่านไปก่อนเช่นexec FOO=bar exec baz
Patrick

14

ในตัวอย่างนี้ไม่มีความแตกต่างที่มีประสิทธิภาพสมมติว่าเชลล์ของคุณเป็นเชลล์ที่เข้ากันได้กับ POSIX และสมมติว่าbazเป็นไฟล์ที่เรียกใช้งานได้และไม่ใช่เชลล์ในตัว

หากเชลล์ของคุณไม่ใช่เชลล์ที่เข้ากันได้กับ POSIX ตัวอย่างเช่นcshหรือtcshไวยากรณ์

FOO=bar baz

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

ถ้าbazเป็น shell builtin เราจะfcยกตัวอย่างเช่นแล้วenvจะไม่ให้ผลลัพธ์เดียวกันเพราะenvกำลังประมวลผลกระบวนการใหม่แทนที่จะเรียกใช้โดยตรงโดย command command นอกจากนี้ยังไม่มีการfcปฏิบัติการจะสามารถทำงานเป็นเพียงเปลือก builtin เพราะวิธีการที่จะมีปฏิสัมพันธ์กับสภาพแวดล้อมเปลือกและอื่น ๆenvจะไม่เคยทำงานร่วมกับ builtin fcเช่น

นอกจากนี้ยังenvมี-iตัวเลือกซึ่งช่วยให้คุณสามารถเริ่มคำสั่งในสภาพแวดล้อมที่ว่างเปล่าที่มีชุดของตัวแปรสภาพแวดล้อมที่ระบุเท่านั้น ดังนั้นenvจะมีประโยชน์มากสำหรับกระบวนการเริ่มต้นในสภาพแวดล้อมที่ผ่านการฆ่าเชื้อเช่น

env -i HOME=/tmp/homedir "PATH=`getconf PATH`" "TERM=$TERM" FOO=bar baz

เมื่อฉันเคยใช้tcshฉันจะเขียน(setenv FOO bar; baz)เพื่อรับฟังก์ชั่นที่เทียบเท่า
Barmar

6

นอกจากสิ่งที่ได้กล่าวไปแล้ว

VAR=value cmd args > redirs

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

ตัวอย่างเช่นคุณไม่สามารถทำได้:

1=foo cmd

หรือ

+++=bar cmd

bash ไม่อนุญาตให้คุณทำ:

SHELLOPTS=xtrace cmd

ในขณะที่คุณสามารถทำได้:

env 1=foo cmd
env +++=bar cmd
env '=baz' cmd

(ไม่ใช่ที่คุณต้องการหรือควรจะทำอย่างนั้น) หรือ:

env SHELLOPTS=xtrace cmd

(บางครั้งฉันต้องทำอย่างนั้น)

โปรดทราบว่าในขณะที่envคุณยังไม่สามารถผ่านสตริงตัวแปรสภาพแวดล้อมที่ไม่มี=(ไม่ใช่ว่าคุณต้องการทำเช่นนั้น)


2

การใช้งานอย่างหนึ่งenvคือการอนุญาตให้$PATHค้นหาไฟล์ที่เรียกใช้งานได้ในแนว Shebang (เนื่องจากenvพิจารณา$PATHเมื่อค้นหาไฟล์ที่เรียกทำงานได้) สิ่งนี้มีประโยชน์หากปฏิบัติการที่คุณต้องการเรียกใช้อาจอยู่ในสถานที่ที่แตกต่างกันบนเครื่องที่แตกต่างกัน ตัวอย่างเช่น,

#!/usr/bin/env perl

ในบรรทัดแรกของสคริปต์ที่มีชุดบิตที่เรียกทำงานได้จะเรียกใช้งานสคริปต์นี้ด้วย Perl ไม่ว่าจะติดตั้งใน/usr/bin/perlหรือใน/usr/local/bin/perlหรือในสถานที่ที่แตกต่างอย่างสิ้นเชิงตราบใดที่ไดเรกทอรีอยู่ในเส้นทาง

แน่นอนว่าการค้นหาเส้นทางมาพร้อมกับความเสี่ยงที่เพิ่มขึ้น แต่จากนั้นความเสี่ยงนั้นไม่ใหญ่กว่าถ้าคุณเขียนไว้อย่างชัดเจนperl yourscript.plซึ่งจะค้นหา Perl ในเส้นทางการค้นหาด้วย


2

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

env -i HOME="$IXD" \
       INFORMIXDIR="$IXD" \
       INFORMIXSERVER="$IXS" \
       ${IXC:+INFORMIXCONCSMCFG="$IXC"} \
       ${IXH:+INFORMIXSQLHOSTS="$IXH"} \
       IFX_LISTEN_TIMEOUT=3 \
       ONCONFIG="onconfig.$IXS" \
       PATH="/bin:/usr/bin:$IXD/bin" \
       SHELL=/bin/ksh \
       TZ=UTC0 \
    $ONINIT "$@"

-iตัวเลือก zaps สภาพแวดล้อมที่มีอยู่ VAR=valueตัวเลือกที่ตามมาตั้งค่าตัวแปรสภาพแวดล้อมที่ฉันต้องการตั้งค่า ชื่อของโปรแกรมที่อยู่ใน$ONINITและอาร์กิวเมนต์บรรทัดคำสั่งใด ๆ "$@"จะถูกส่งผ่านคำต่อคำกับ

การ${IXH:+INFORMIXSQLHOSTS="$IXH"}สร้างจะผ่านINFORMIXSQLHOSTS="$IXH"ไปenvหาก$IXHถูกตั้งค่าเป็นค่าที่ไม่ว่างเปล่า

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