sumber skrip Bash - Return on Error, bukannya Exit?

15

Saya sumber skrip bash di terminal , jadi keluar dari kesalahan dengan

set -o errexit

membunuh terminal saya, yang sangat LUAR BIASA, karena saya harus menutup terminal, buka yang lain, dan reset beberapa variabel.

Sejauh ini, menggunakan

command || return

baris, dalam skrip, melakukan apa yang saya inginkan

set -o errexit

untuk melakukan ... Tapi saya ingin itu dilakukan untuk seluruh skrip; bukan hanya satu baris / perintah

Saya memiliki file yang penuh dengan perintah untuk mengatur situs, dan saya lebih suka tidak melakukan perintah || kembali

untuk setiap baris dalam file

Apakah ada opsi set lain, atau sesuatu yang hanya akan "kembali" alih-alih keluar dari terminal?

- Hanya untuk kejelasan , saya ingin membunuh skrip, dan meninggalkan terminal dalam keadaan yang sama yang menekan ctrl + C untuk membunuh layanan yang berjalan di terminal. command || returnapakah itu. Tapi saya tidak ingin menempel || returnke setiap baris dalam file. Jadi saya mencari sesuatu yang mirip set -o errexit, yang tidak menyebabkan terminal mati

--- Catatan: Membuat skrip bodoh dengan dua baris di dalamnya (super.sh):

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

Dan menempatkan set -o errexitdi bagian atas create.sh,

bekerja persis seperti yang saya harapkan. Namun, itu benar-benar bodoh harus membuat file dengan dua baris di dalamnya, hanya untuk memanggil skrip bash, bukan hanya memanggilnya dari terminal. Ugghhh

inilah beberapa contoh:

di super.sh

#!/bin/bash

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

di 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

di terminal:

 $ bash super.sh

output seperti yang diharapkan:

my-mac$

Ini bekerja. Solusi yang menjengkelkan.

Idealnya, saya ingin mengeksekusi apa yang ada di file super.sh bodoh dari terminal, bukan file super.sh: D, tanpa terminal mematikan saya. Inilah yang terjadi dengan apa yang saya coba lakukan:

perintah terminal:

my-mac$ source $create_path blah

di create.sh saya masih punya set -o errexit

Inilah output pada terminal

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

[Process completed]

Dan kemudian terminal dibekukan. Ctrl + C tidak berfungsi, begitu juga Ctrl + D

Jika alih-alih set -o errexit, jika saya hanya menggunakan command || returnpernyataan di mana-mana di file create.sh, maka saya mendapatkan apa yang saya inginkan, sambil mengeksekusi baris di supser.sh langsung di terminal (alih-alih memanggil super.sh dari terminal). Tapi itu juga bukan solusi yang praktis.

Catatan: Saya menyukai jawaban @terdon tentang hanya menelurkan shell anak jadi saya akhirnya hanya menelurkan sub shell melalui skrip alih-alih terminal, karena ia menunjukkan dalam jawabannya menggunakan kawat gigi ( ), di sekitar seluruh skrip .. Jawabannya bekerja juga.


sumber
Apakah Anda melakukan ini dalam skrip atau secara manual?
terdon
Saya memanggil file dengan sumber di terminal. Seperti dalam: source $file_path argumentSkrip dieksekusi dalam shell yang sama dengan yang saya sebut dari (apa source, saya telah diberitahu ... dan bertindak seperti itu) command || returnpernyataan dalam file yang saya
OK, dan di mana set dijalankan? Apakah itu dalam skrip bersumber atau Anda menjalankannya secara manual? Ini akan jauh lebih mudah untuk dijawab jika Anda dapat menambahkan contoh sederhana yang dapat kami salin dan coba. Saya punya ide, tapi saya perlu cara pengujian untuk memastikan itu berhasil.
terdon
Saya menambahkan Catatan ke posting asli yang mungkin bisa membantu. Tetapi saya juga akan melakukan apa yang Anda sarankan.

Jawaban:

4

Cukup sumber file dengan failafe:

source the-source-file || true

... maka perintah keseluruhan tidak akan gagal, bahkan jika sourcetidak.

Jeff Schaller
sumber
Sebenarnya, saya pikir ini yang saya inginkan, tetapi ternyata terminal saya lambat ... Saya sebenarnya ingin kembali ke terminal karena kesalahan, (artinya hentikan seluruh skrip di treknya) ... untuk alasan apa pun, source file || true tidak melakukan ini, juga tidak source file || return ketika saya mengetik ini ke terminal ...
Sumber file tidak mengembalikan Anda ke prompt shell ??
Jeff Schaller
inilah yang ada di terminal saya: Jills-MBP:~ jillr$ source ~/Desktop/site_builder/create.sh blah || trueIni hanya mengeksekusi bagian selanjutnya dari skrip pada gagal, jadi kembali bukan benar. Satu-satunya hal yang berhasil adalah command || returnpernyataan dalam file aktual untuk semua perintah, yang konyol. Saya tidak tahu apakah melempar semuanya ke dalam fungsi kemudian memanggil function || returndi akhir file akan ada gunanya juga.
Nah, jika Anda secara eksplisit memakai || returnperintah yang gagal, ya, itu akan kembali. Saya pikir kami berusaha menjaga agar shell induk / induk Anda tidak keluar?
Jeff Schaller
Ya, saya ingin terminal tidak keluar. Karena saya tidak ingin keluar dari terminal. Saya ingin keluar dari skrip. Kembali pada perintah individu dalam skrip keluar dari skrip dan meninggalkan terminal saya dalam kondisi yang sama seperti menekan Ctrl + C untuk mematikan proses, seperti menjalankan server dari terminal, akan. Saya ingin menghindari perintah penulisan || kembali untuk setiap baris dalam file: D
2

Ini adalah satu-satunya hal yang berfungsi untuk apa yang saya perlu capai (menciptakan lingkungan virtual kemudian mengaktifkannya, kemudian menginstal persyaratan dari skrip bash):

menelurkan shell subkulit / anak dari skrip, seperti pada:

stupid_file.sh

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

jalankan stupid_file menggunakan:

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

TAMAT.

** Membungkuk **

(kredit jatuh ke Jeff dan Terdon)


sumber
1
Ini tidak benar-benar berbeda dari hanya menjalankan skrip alih-alih sumbernya.
chepner
@ chepner hmmm. Keren. Saya harus mencoba menelepon adil bash $create_path blahdan melihat apakah masih keluar, dan mengeksekusi dengan cara yang sama, dan masih menginstal barang ke lingkungan virtual saya dengan benar. Kehabisan waktu sekarang.
Saya akan menghemat waktu Anda: itu tidak akan (jika dengan "menginstal barang" Anda berarti mengatur variabel lingkungan di shell Anda saat ini), dan juga tidak akan (...), karena semua tugas dalam tanda kurung hanya mempengaruhi subkulit itu. foo=3; (foo=5); echo "$foo"akan menampilkan 3, bukan 5.
chepner
@ mitra tidak persis. Saya tidak dapat menelepon source filedari terminal dan mengharapkan hasil yang sama. Karena itu tidak pernah berhasil. Satu-satunya waktu saya mendapatkan hasil yang sama adalah ketika saya membuat sub shell secara eksplisit, apakah melalui terminal, atau dari skrip. Namun saya dapat menggunakan bashalih-alih sourceuntuk mengeksekusi skrip, dan mendapatkan hasil yang sama, tetapi hanya ketika saya mengeksekusi skrip saya di sub shell secara eksplisit
@ mitra dengan menginstal barang, maksud saya sebenarnya menciptakan lingkungan virtual, aktifkan lingkungan virtual itu, dan kemudian jalankan di pip install -r $apath/requirements.txtdalam lingkungan yang diaktifkan itu. Itu sebabnya saya menggunakan sumber untuk memanggil script
0

Sebagai solusi sederhana, Anda dapat menjalankan shell di shell Anda saat ini dan sumber di sana. Sesuatu seperti:

  1. Buka terminal baru dan atur semuanya sesuai keinginan Anda. Anda menyebutkan beberapa variabel lingkungan dan sejenisnya. Atur mereka di sini.

  2. Di terminal itu, mulai shell baru. Misalnya bash,.

  3. Lakukan pekerjaanmu. Sumber skrip Anda. Jika keluar, Anda baru saja dilemparkan ke dalam shell pertama dan semuanya masih diatur. Jalankan bashkembali dan Anda kembali dalam bisnis.

Sebagai ilustrasi, saya membuat skrip ini yang akan gagal jika Anda mencoba untuk sumbernya:

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

Mari kita lihat apa yang terjadi jika saya memulai sesi shell bersarang dan kemudian sumber itu (catatan bahwa saya menggunakan nama portabel untuk sourceperintah, .; sourceadalah bashism a):

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 $ 

Seperti yang Anda lihat, kesalahan sintaksis menyebabkan skrip bersumber untuk keluar yang, pada gilirannya menyebabkan sesi shell saya keluar tetapi karena itu adalah sesi bersarang, yang baru saja membuat saya kembali ke aslinya, shell induk dengan semua variabel masih mengatur . Sekarang, jalankan lagi shell baru dan Anda dapat kembali ke sumber skrip Anda.

terdon
sumber
Saya akan mencoba ini sangat cepat
Ini memiliki efek yang dimaksudkan ... downside adalah bahwa variabel yang saya buat untuk shell induk, tidak dapat diakses di shell anak, yang berisi salah satu variabel yang saya butuhkan untuk dieksekusi di shell anak. Apakah ada cara untuk menelurkan subkulit dari file yang saya jalankan? Dengan begitu, saya masih bisa memanggil skrip di shell induk, dan masih bisa mengakses variabel yang saya butuhkan? Saya benar-benar pengaturan create_path=~/Desktop/site_builder/create.sh di shell orangtua karena saya sering melakukannya. Dan saya membutuhkannya untuk memanggil sumber $ create_path [argumen] untuk mengeksekusi skrip.
1
@JillRussek jika variabel tidak diteruskan ke shell anak, Anda tidak akan melakukannya export. Tetapi apa yang Anda gambarkan benar-benar sangat tidak masuk akal. Ini terdengar lebih dan lebih seperti masalah XY . Anda mungkin ingin memposting pertanyaan baru yang menjelaskan apa tujuan akhir Anda. Saya yakin kami bisa memberikan Anda solusi yang lebih baik dari semua sumber aneh ini.
terdon
Hmm. Saya mungkin mencobanya juga. Saat ini, hanya menelurkan shell anak dari skrip alih-alih dari terminal melakukan apa yang saya inginkan. Saya harus sumber skrip dari terminal untuk menciptakan lingkungan virtual dalam skrip, dan pip instal barang-barang di dalamnya. Ini berfungsi sebagaimana dimaksud sekarang.
Tapi Anda benar, saya tidak mengekspor variabel, karena saya tidak tahu saya perlu: D. (Saya tidak pernah melahirkan cangkang anak sebelumnya)