การหาสคริปต์ Bash - ส่งคืนข้อผิดพลาดแทนที่จะออกหรือไม่


17

ฉันกำลังหาสคริปต์ทุบตีในเทอร์มินัลดังนั้นออกจากข้อผิดพลาดด้วย

set -o errexit

ฆ่า terminal ของฉันซึ่งเป็นสิ่งที่น่ารำคาญอย่างมากเพราะฉันต้องปิดเครื่องเทอร์มินัลเปิดอีกอันหนึ่งและรีเซ็ตตัวแปรบางตัว

จนถึงตอนนี้การใช้

command || return

บรรทัดในสคริปต์ทำสิ่งที่ฉันต้องการอย่างแน่นอน

set -o errexit

ที่จะทำ ... แต่ฉันต้องการให้มันทำเพื่อทั้งสคริปต์; ไม่ใช่แค่หนึ่งบรรทัด / คำสั่ง

ฉันมีไฟล์ที่เต็มไปด้วยคำสั่งสำหรับการตั้งค่าไซต์และฉันไม่ควรทำคำสั่ง || กลับ

สำหรับทุก ๆ บรรทัดในไฟล์

มีตัวเลือกชุดอื่นหรืออะไรที่จะ "คืน" แทนที่จะออกจากเทอร์มินัล

- เพื่อความชัดเจนฉันต้องการฆ่าสคริปต์และออกจากเทอร์มินัลในสถานะเดียวกับที่กด ctrl + C เพื่อฆ่าเซอร์วิสที่รันในเทอร์มินัล command || returnทำอย่างนั้น แต่ฉันไม่ต้องการที่จะยึดติด|| returnกับทุกบรรทัดในไฟล์ ดังนั้นฉันกำลังมองหาสิ่งที่คล้ายกับset -o errexitที่ไม่ได้ทำให้สถานีปิดตัวลง

--- หมายเหตุ: การสร้างสคริปต์โง่ที่มีสองบรรทัดในนั้น (super.sh):

create_path=~/Desktop/site_builder/create.sh
source $create_path blah

และวางset -o errexitที่ด้านบนของ create.sh

ทำงานตรงตามที่ฉันคาดไว้ อย่างไรก็ตามมันโง่จริงๆที่จะต้องสร้างไฟล์ที่มีสองบรรทัดในนั้นเพียงเพื่อเรียกสคริปต์ทุบตีอีกตัวแทนที่จะเรียกมันจากเทอร์มินัล Ugghhh

นี่คือตัวอย่างบางส่วน:

ใน super.sh

#!/bin/bash

create_path=~/Desktop/site_builder/create.sh
source $create_path blah

ใน create.sh

#!/bin/bash
set -o errexit
#line below this is a line that fails and will cause the script to stop and return to the terminal as expected 
sed "s/@@SITE_NAME@@/$dirname" 
~/Desktop/site_builder/template_files/base.html > ~/Desktop/$dirname/templates/base.html # a line with a stupid error

ใน terminal:

 $ bash super.sh

ผลผลิตตามที่คาดไว้:

my-mac$

วิธีนี้ใช้ได้ผล ช่างเป็นทางออกที่น่ารำคาญ

ฉันต้องการที่จะดำเนินการในไฟล์ stupid super.sh จากเทอร์มินัลไม่ใช่ไฟล์ super.sh: D โดยไม่ต้องปิดเครื่อง นี่คือสิ่งที่เกิดขึ้นกับสิ่งที่ฉันพยายามทำ:

คำสั่ง terminal:

my-mac$ source $create_path blah

ใน create.sh ฉันยังมี set -o errexit

นี่คือผลลัพธ์ที่เทอร์มินัล

    sed: 1: "s/@@SITE_NAME@@/blah": unterminated substitute in regular expression
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

[Process completed]

จากนั้นเทอร์มินัลจะถูกแช่แข็ง Ctrl + C ไม่ทำงานไม่มี Ctrl + D

ถ้าset -o errexitหากฉันใช้command || returnคำสั่งทุกที่ในไฟล์ create.sh ฉันก็จะได้สิ่งที่ฉันต้องการอย่างแน่นอนในขณะที่รันบรรทัดใน supser.sh บนเทอร์มินัลโดยตรง (แทนที่จะเรียก super.sh จากเทอร์มินัล) แต่นั่นไม่ใช่วิธีแก้ปัญหาในทางปฏิบัติเช่นกัน

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


คุณกำลังทำสิ่งนี้ด้วยสคริปต์หรือด้วยตนเอง
terdon

ฉันกำลังเรียกไฟล์พร้อมแหล่งที่มาในเทอร์มินัล เช่นเดียวกับใน: source $file_path argumentสคริปต์จะถูกดำเนินการในเปลือกเดียวกันที่ฉันเรียกว่าจาก (สิ่งที่sourceฉันได้รับการบอก ... และทำหน้าที่เหมือนกรณี) command || returnงบอยู่ในไฟล์ที่ฉันกำลังดำเนินการใน terminal

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

ฉันเพิ่มหมายเหตุในโพสต์ดั้งเดิมที่อาจช่วยได้ แต่ฉันก็จะทำตามที่คุณแนะนำ

คำตอบ:


5

เพียงแค่ส่งไฟล์โดยที่ไม่ปลอดภัย:

source the-source-file || true

... ดังนั้นคำสั่งโดยรวมจะไม่ล้มเหลวแม้ว่าsourceจะเป็นเช่นนั้น


ที่จริงแล้วฉันคิดว่านี่เป็นสิ่งที่ฉันต้องการ แต่กลับกลายเป็นว่าเทอร์มินัลของฉันกำลังช้า ... ฉันต้องการกลับไปที่เทอร์มินัลด้วยความผิดพลาด (หมายถึงหยุดสคริปต์ทั้งหมดในแทร็ก) .. ด้วยเหตุผลใดก็ตามsource file || true ไม่ทำเช่นนี้ไม่ทำsource file || return เมื่อฉันพิมพ์สิ่งนี้ลงในเทอร์มินัล ...

การหาไฟล์จะไม่ส่งคืนเชลล์ให้คุณ?
Jeff Schaller

นี่คือสิ่งที่อยู่ใน terminal ของฉัน: Jills-MBP:~ jillr$ source ~/Desktop/site_builder/create.sh blah || trueมันดำเนินการส่วนต่อไปของสคริปต์เมื่อล้มเหลวดังนั้นจะกลับมาจริงแทน สิ่งเดียวที่ทำงานได้คือcommand || returnคำสั่งในไฟล์จริงสำหรับคำสั่งทั้งหมดซึ่งโง่ ฉันไม่รู้ว่าการขว้างมันทั้งหมดในฟังก์ชั่นการโทรfunction || returnที่ท้ายไฟล์จะทำอะไรได้ดีเช่นกัน

ถ้าคุณใส่|| returnคำสั่งที่ล้มเหลวอย่างชัดเจนใช่มันจะกลับมา ฉันคิดว่าเราพยายามป้องกันไม่ให้เชลล์หลัก / พาเรนต์ของคุณออก?
Jeff Schaller

ใช่ฉันต้องการป้องกันมิให้มีการออกจากเครื่อง เพราะฉันไม่ต้องการออกจากสถานี ฉันต้องการออกจากสคริปต์ ย้อนกลับไปที่แต่ละคำสั่งในสคริปต์ออกจากสคริปต์และปล่อยให้เทอร์มินัลของฉันอยู่ในสภาพเดียวกับการกด Ctrl + C เพื่อฆ่ากระบวนการเช่นการรันเซิร์ฟเวอร์ในรูปแบบเทอร์มินัล ฉันต้องการหลีกเลี่ยงการเขียนคำสั่ง || กลับสำหรับทุกบรรทัดในไฟล์: D

3

นี่เป็นสิ่งเดียวที่ทำงานได้กับสิ่งที่ฉันต้องการเพื่อให้บรรลุผล (การสร้างสภาพแวดล้อมเสมือนจริงจากนั้นเปิดใช้งานจากนั้นติดตั้งข้อกำหนดจากสคริปต์ทุบตี):

วางไข่เชลล์ย่อย / ชายด์เชลล์จากสคริปต์ดังที่:

stupid_file.sh

(
set -o errexit
#bunch of commands
#one line fails
)

เรียกใช้ stupid_file โดยใช้:

source stupid_file.sh <file arguments here> || true

ตอนจบ.

** ใช้ธนู

(เครดิตไปที่ Jeff และ Terdon)


1
สิ่งนี้ไม่ได้แตกต่างไปกว่าเพียงแค่เรียกใช้งานสคริปต์แทนการจัดหามัน
chepner

@chepner hmmm เย็น. ฉันจะต้องลองโทรออกเพื่อbash $create_path blahดูว่ายังมีอยู่หรือไม่และดำเนินการในลักษณะเดียวกันและยังคงติดตั้งข้อมูลลงในสภาพแวดล้อมเสมือนจริงของฉันอย่างถูกต้อง หมดเวลาแล้ว

ฉันจะช่วยคุณประหยัดเวลา: มันจะไม่ (ถ้าหาก "ติดตั้งเนื้อหา" คุณหมายถึงตั้งค่าตัวแปรสภาพแวดล้อมในเชลล์ปัจจุบันของคุณ) และจะไม่ทำ(...)เช่นนั้นเนื่องจากการมอบหมายทั้งหมดในวงเล็บจะมีผลกับเชลล์ย่อยเท่านั้น foo=3; (foo=5); echo "$foo"จะส่งออก 3 ไม่ใช่ 5
chepner

@chepner ไม่แน่นอน ฉันไม่สามารถโทรsource fileจากเทอร์มินัลและคาดหวังผลลัพธ์เดียวกัน เพราะนั่นไม่เคยทำงาน ครั้งเดียวที่ฉันได้ผลลัพธ์เดียวกันคือเมื่อฉันสร้างเชลล์ย่อยอย่างชัดเจนไม่ว่าจะผ่านเทอร์มินัลหรือจากสคริปต์ ฉันสามารถใช้bashแทนsourceการรันสคริปต์และได้ผลลัพธ์เดียวกัน แต่เมื่อฉันรันสคริปต์ในเชลล์ย่อยอย่างชัดเจน

@chepner โดยการติดตั้งสิ่งของฉันหมายถึงการสร้างสภาพแวดล้อมเสมือนจริงเปิดใช้งานสภาพแวดล้อมเสมือนจริงจากนั้นดำเนินการpip install -r $apath/requirements.txtภายในสภาพแวดล้อมที่เปิดใช้งานนั้น นั่นเป็นเหตุผลที่ฉันใช้แหล่งข้อมูลในตอนแรกเพื่อโทรหาสคริปต์

1

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

  1. เปิดเทอร์มินัลใหม่และตั้งค่าทุกอย่างตามที่คุณต้องการ คุณพูดถึงตัวแปรสภาพแวดล้อมบางอย่างและไม่ชอบ ตั้งพวกเขาที่นี่

  2. ในเทอร์มินัลนั้นให้เริ่มเชลล์ใหม่ bashยกตัวอย่างเช่น

  3. ทำในสิ่งที่คุณ แหล่งสคริปต์ของคุณ ถ้ามันออกคุณจะถูกโยนเข้าไปในกระสุนนัดแรกและทุกอย่างก็ยังตั้งค่าอยู่ เพิ่งทำงานbashอีกครั้งและคุณกลับมาทำธุรกิจ

เพื่อแสดงให้เห็นว่าฉันสร้างสคริปต์นี้ซึ่งจะล้มเหลวถ้าคุณพยายามที่จะมามัน:

$ cat /home/terdon/scripts/bar.sh
set -o errexit
var='bar

เรามาดูกันว่าจะเกิดอะไรขึ้นถ้าฉันเริ่มต้นเซสชั่นเชลล์ที่ซ้อนกันและจากนั้นแหล่งที่มามัน (โปรดทราบว่าฉันกำลังใช้ชื่อแบบพกพาสำหรับsourceคำสั่ง.; sourceเป็น bashism):

parent-shell $ bash      ## start a new shell
child-shell $ . ~/scripts/bar.sh
bash: /home/terdon/scripts/bar.sh: line 2: unexpected EOF while looking for matching `''
parent-shell $ 

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


ฉันจะลองทำสิ่งนี้อย่างรวดเร็วจริงๆ

สิ่งนี้มีผลตามที่ตั้งใจ ... ข้อเสียคือตัวแปรที่ฉันสร้างสำหรับเปลือกหลักไม่สามารถเข้าถึงได้ในเปลือกลูกซึ่งมีหนึ่งในตัวแปรที่ฉันต้องการสำหรับการดำเนินการในเปลือกลูก มีวิธีวางไข่ subshell จากไฟล์ที่ฉันกำลังทำงานหรือไม่? ด้วยวิธีนี้ฉันยังสามารถเรียกใช้สคริปต์ในเชลล์พาเรนต์และยังสามารถเข้าถึงตัวแปรที่ฉันต้องการได้? ฉันตั้งค่าอย่างแท้จริงcreate_path=~/Desktop/site_builder/create.sh ในเปลือกหลักเพราะฉันทำบ่อย และฉันต้องการมันเพื่อเรียกซอร์ส $ create_path [อาร์กิวเมนต์] เพื่อเรียกใช้งานสคริปต์

1
@JillRussek หากตัวแปรไม่ได้ถูกส่งผ่านไปยัง child shell คุณไม่ได้ใช้exportมัน แต่สิ่งที่คุณอธิบายมีความหมายน้อยมาก มันฟังดูเป็นปัญหามากขึ้นเรื่อย ๆ คุณอาจต้องการโพสต์คำถามใหม่เพื่ออธิบายว่าเป้าหมายของคุณคืออะไร ฉันพนันได้ว่าเราจะให้ทางออกที่ดีกว่าแก่คุณในการหาแหล่งที่แปลก
terdon

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

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