Edit skrip shell saat sedang berjalan


95

Dapatkah Anda mengedit skrip shell saat sedang berjalan dan apakah perubahannya memengaruhi skrip yang sedang berjalan?

Saya ingin tahu tentang kasus spesifik dari skrip csh yang saya miliki batch menjalankan banyak rasa build yang berbeda dan berjalan sepanjang malam. Jika sesuatu terjadi pada saya di tengah operasi, saya ingin masuk dan menambahkan perintah tambahan, atau mengomentari perintah yang tidak dijalankan.

Jika tidak memungkinkan, apakah ada shell atau mekanisme batch yang memungkinkan saya melakukan ini?

Tentu saja saya sudah mencobanya, tetapi akan memakan waktu berjam-jam sebelum saya melihat apakah itu berhasil atau tidak, dan saya ingin tahu tentang apa yang terjadi atau tidak terjadi di balik layar.


1
Saya telah melihat dua hasil dari mengedit file skrip untuk skrip yang sedang berjalan: 1) perubahan diabaikan seolah-olah telah membaca semuanya ke dalam memori atau 2) skrip macet dengan kesalahan seolah-olah telah membaca sebagian dari perintah. Saya tidak tahu apakah itu tergantung pada ukuran skrip. Bagaimanapun, saya tidak akan mencobanya.
Paul Tomblin

Singkatnya: tidak, kecuali itu merujuk pada diri sendiri / menelepon, dalam hal ini skrip utama akan tetap menjadi yang lama.
Wrikken

Ada dua pertanyaan penting di sini. 1) Bagaimana cara menambahkan perintah dengan benar dan aman ke skrip yang sedang berjalan? 2) Ketika saya mengubah skrip yang sedang berjalan, apa yang akan terjadi?
Chris Quenelle

3
Pertanyaannya adalah apakah shell menjalankan skrip dengan membaca seluruh file skrip dan kemudian mengeksekusinya, atau dengan membacanya sebagian saat dijalankan. Saya tidak tahu yang mana; itu bahkan mungkin tidak ditentukan. Anda harus menghindari bergantung pada salah satu perilaku.
Keith Thompson

Jawaban:


-68

Skrip tidak berfungsi seperti itu; salinan yang dijalankan tidak bergantung pada file sumber yang Anda edit. Lain kali skrip dijalankan, ini akan didasarkan pada versi file sumber yang terakhir disimpan.

Mungkin bijaksana untuk memecah skrip ini menjadi beberapa file, dan menjalankannya satu per satu. Ini akan mengurangi waktu eksekusi hingga gagal. (yaitu, bagi batch menjadi satu skrip ragam build, jalankan masing-masing skrip satu per satu untuk melihat mana yang menyebabkan masalah).


68
Saya telah mengamati yang sebaliknya. Menjalankan skrip bash yang diedit dapat menyebabkan skrip yang sedang berjalan macet karena file tampaknya bergerak di bawah posisi file pembacaan skrip bash.
Tilman Vogel

10
Dalam pengalaman saya di banyak sistem, salinan yang menjalankan TIDAK independen dari file disk, itulah mengapa masalah ini sangat mengejutkan dan penting dalam pemrograman skrip shell.
Chris Quenelle

6
Ini jelas tidak terlepas dari file pada disk. Shell biasanya hanya membaca skrip dalam blok, misalnya 128 byte atau 4096 byte atau 16384 byte, dan hanya membaca blok berikutnya ketika membutuhkan input baru. (Anda dapat melakukan hal-hal seperti lsof pada shell yang menjalankan skrip dan melihatnya masih membuka file.)
mirabilos

5
Tidak. Sebenarnya jika Anda mengedit skrip, ini menyebabkan proses gagal.
Erik Aronesty

8
Anda tidak benar. Itu buffer tergantung pada implementasi dan perintah yang sebenarnya dipanggil dalam skrip, apakah stdout diarahkan ke file, ada banyak faktor dan jawaban Anda tidak hanya benar.
GL2014

51

Itu memang memengaruhi, setidaknya pesta di lingkungan saya, tetapi dengan cara yang sangat tidak menyenangkan . Lihat kode-kode ini. Pertamaa.sh :

#!/bin/sh

echo "First echo"
read y

echo "$y"

echo "That's all."

b.sh:

#!/bin/sh

echo "First echo"
read y

echo "Inserted"

echo "$y"

# echo "That's all."

Melakukan

$ cp a.sh run.sh
$ ./run.sh
$ # open another terminal
$ cp b.sh run.sh  # while 'read' is in effect
$ # Then type "hello."

Dalam kasus saya, hasilnya selalu:

Halo
Halo
Itu saja.
Itu saja.

(Tentu saja jauh lebih baik untuk mengotomatiskannya, tetapi contoh di atas dapat dibaca.)

[Sunting] Ini tidak dapat diprediksi, dengan demikian berbahaya. Solusi terbaik adalah , seperti yang dijelaskan di sini, masukkan semua ke dalam penjepit, dan sebelum penjepit penutup, masukkan "keluar" . Baca jawaban terkait dengan baik untuk menghindari jebakan.

[ditambahkan] Perilaku sebenarnya bergantung pada satu baris baru tambahan, dan mungkin juga pada rasa Unix Anda, sistem file, dll. Jika Anda hanya ingin melihat beberapa pengaruh, cukup tambahkan "echo foo / bar" ke b.sh sebelum dan / atau sesudahnya baris "baca".


3
Mh, saya tidak melihat kasih sayang. Apakah saya melewatkan sesuatu?
pengguna tidak diketahui

Perilaku yang tepat bergantung pada satu baris baru tambahan , dan mungkin juga pada flavor Unix, filesystem, dll, meskipun tidak yakin. Jika Anda hanya ingin melihat pengaruh apa pun, cukup perbesar b.shdengan menambahkan 10 baris echo foo / bar / baz. Inti dari jawaban oleh dave4220 dan saya adalah bahwa efeknya tidak mudah diprediksi. (BTW kata benda "kasih sayang" berarti "cinta" =)
teika kazura

ya, itu sangat rusak. saya punya solusi (di bawah). yang lebih berbahaya adalah pembaruan svn / rsync / git
Erik Aronesty

40

Coba ini ... buat file bernama bash-is-odd.sh:

#!/bin/bash
echo "echo yes i do odd things" >> bash-is-odd.sh

Itu menunjukkan bahwa bash memang menafsirkan skrip "saat Anda pergi". Memang, mengedit skrip yang berjalan lama memiliki hasil yang tidak dapat diprediksi, memasukkan karakter acak, dll. Mengapa? Karena bash membaca dari posisi byte terakhir, jadi pengeditan menggeser lokasi karakter saat ini yang sedang dibaca.

Singkatnya, Bash sangat, sangat tidak aman karena "fitur" ini. svn dan rsyncketika digunakan dengan skrip bash sangat mengganggu, karena secara default mereka "menggabungkan" hasil ... pengeditan di tempat. rsyncmemiliki mode yang memperbaikinya. svn dan git tidak.

Saya menyajikan solusi. Buat file bernama /bin/bashx:

#!/bin/bash
source "$1"

Sekarang gunakan #!/bin/bashxpada skrip Anda dan selalu jalankan dengan bashxbukan bash. Ini memperbaiki masalah - Anda dapat dengan aman rsyncmembuat skrip Anda.

Solusi alternatif (in-line) yang diusulkan / diuji oleh @ AF7:

{
   # your script
} 
exit $?

Kawat gigi keriting melindungi dari pengeditan, dan perlindungan keluar dari penambahan. Tentu saja, kita semua akan jauh lebih baik jika bash hadir dengan opsi, seperti -w(seluruh file), atau sesuatu yang melakukan ini.


1
Btw; inilah nilai tambah untuk mengatasi kekurangan dan karena saya suka jawaban Anda yang telah diedit.
Andrew Barber

1
Saya tidak bisa merekomendasikan ini. Dalam solusi ini, parameter posisi digeser satu. Ingat juga bahwa Anda tidak dapat menetapkan nilai ke $ 0. Artinya jika Anda hanya mengubah "/ bin / bash" menjadi "/ bin / bashx", banyak skrip yang gagal.
teika kazura

1
Tolong beritahu saya bahwa opsi seperti itu telah diterapkan!
AF7

10
Solusi sederhana, disarankan kepada saya oleh teman saya Giulio (kredit dimana jatuh tempo) adalah dengan memasukkan {di awal dan} di akhir naskah. Bash dipaksa untuk membaca semua yang ada di memori.
AF7

1
@ AF7 meningkatkan solusi teman Anda: {your_code; } && keluar; akan mencegah baris yang ditambahkan ke akhir dieksekusi juga.
korkman

17

Pisahkan skrip Anda menjadi beberapa fungsi, dan setiap kali suatu fungsi memanggil Anda sourcedari file terpisah. Kemudian Anda dapat mengedit file kapan saja dan skrip Anda yang sedang berjalan akan mengambil perubahan saat bersumber lagi.

foo() {
  source foo.sh
}
foo

Saya telah menggunakan teknik ini secara efektif untuk sementara waktu sekarang untuk memperbarui skrip build saya yang sudah berjalan lama saat mereka berjalan. Saya ingin mempelajari teknik untuk membuat file saat ini dibaca hingga akhir file, sehingga saya tidak perlu memiliki dua file untuk mengimplementasikan setiap skrip shell.
Chris Quenelle

3

Pertanyaan bagus! Semoga skrip sederhana ini membantu

#!/bin/sh
echo "Waiting..."
echo "echo \"Success! Edits to a .sh while it executes do affect the executing script! I added this line to myself during execution\"  " >> ${0}
sleep 5
echo "When I was run, this was the last line"

Tampaknya di bawah linux bahwa perubahan yang dilakukan pada eksekusi .sh diberlakukan oleh skrip pelaksana, jika Anda dapat mengetik cukup cepat!


2

Catatan tambahan yang menarik - jika Anda menjalankan skrip Python itu tidak berubah. (Ini mungkin sangat jelas bagi siapa pun yang memahami bagaimana shell menjalankan skrip Python, tetapi berpikir ini mungkin pengingat yang berguna bagi seseorang yang mencari fungsi ini.)

Saya menciptakan:

#!/usr/bin/env python3
import time
print('Starts')
time.sleep(10)
print('Finishes unchanged')

Kemudian di shell lain, saat ini sedang tidur, edit baris terakhir. Saat ini selesai, ini akan menampilkan garis tidak berubah, mungkin karena menjalankan .pyc? Hal yang sama terjadi di Ubuntu dan macOS.


1

Saya belum menginstal csh, tapi

#!/bin/sh
echo Waiting...
sleep 60
echo Change didn't happen

Jalankan itu, edit baris terakhir dengan cepat untuk dibaca

echo Change happened

Outputnya adalah

Waiting...
/home/dave/tmp/change.sh: 4: Syntax error: Unterminated quoted string

Hrmph.

Saya kira pengeditan pada skrip shell tidak akan berpengaruh sampai mereka dijalankan ulang.


2
Anda harus meletakkan string yang ingin Anda tampilkan dalam tanda kutip.
pengguna1463308

2
sebenarnya, ini membuktikan bahwa editor Anda tidak berfungsi seperti yang Anda pikirkan. banyak, banyak editor (termasuk vim, emacs) beroperasi pada file "tmp", dan bukan file live. Coba gunakan "echo 'echo uh oh' >> myshell.sh" daripada vi / emacs ... dan perhatikan saat ia mengeluarkan hal baru. Lebih buruk lagi ... svn dan rsync juga mengedit dengan cara ini!
Erik Aronesty

3
-1. Kesalahan itu tidak terkait dengan file yang sedang diedit: itu karena Anda menggunakan tanda kutip! Itu bertindak sebagai kutipan tunggal, menyebabkan kesalahan. Letakkan seluruh string itu dalam tanda kutip ganda dan coba lagi.
Penguin Anonim

5
Fakta bahwa kesalahan terjadi menunjukkan bahwa pengeditan tidak memiliki efek yang diinginkan.
danmcardle

@danmcardle Siapa yang tahu? Mungkin bash saw Change didn'ned.
Kirill Bulygin

1

Jika ini semua dalam satu skrip, maka tidak itu tidak akan berhasil. Namun, jika Anda mengaturnya sebagai skrip driver yang memanggil sub-skrip, maka Anda mungkin dapat mengubah sub-skrip sebelum dipanggil, atau sebelum dipanggil lagi jika Anda melakukan perulangan, dan dalam hal ini saya percaya perubahan itu akan tercermin dalam eksekusi.


0

Saya tidak mendengar ... tapi bagaimana dengan beberapa tipuan:

BatchRunner.sh

Command1.sh
Command2.sh

Command1.sh

runSomething

Command2.sh

runSomethingElse

Maka Anda harus dapat mengedit konten setiap file perintah sebelum BatchRunner melakukannya, bukan?

ATAU

Versi yang lebih bersih akan membuat BatchRunner melihat ke satu file di mana ia akan menjalankan satu baris secara berurutan. Maka Anda harus bisa mengedit file kedua ini saat file pertama berjalan, bukan?


Saya ingin tahu apakah itu memuatnya ke dalam memori untuk menjalankannya dan perubahan tidak masalah setelah proses utama dimulai ...
Eric Hodonsky

0

Gunakan Zsh sebagai gantinya untuk skrip Anda.

AFAICT, Zsh tidak menunjukkan perilaku yang membuat frustrasi ini.


Inilah alasan # 473 lebih memilih Zsh daripada pesta. Saya baru-baru ini sedang mengerjakan skrip bash lama yang membutuhkan waktu 10m untuk dijalankan, dan saya tidak dapat mengeditnya sambil menunggu hingga selesai!
Micah Elliott

-5

biasanya, tidak biasa mengedit skrip Anda saat sedang berjalan. Yang harus Anda lakukan adalah melakukan pemeriksaan kendali atas operasi Anda. Gunakan pernyataan if / else untuk memeriksa kondisi. Jika ada yang gagal, lakukan ini, kalau tidak lakukan itu. Itulah cara untuk pergi.


Ini sebenarnya bukan tentang kegagalan skrip daripada memutuskan untuk mengubah pekerjaan batch di tengah operasi. IE menyadari bahwa masih ada lagi yang ingin saya kompilasi, atau bahwa saya tidak memerlukan pekerjaan tertentu yang sudah dalam antrean.
ack

1
Jika Anda benar-benar menambahkan ke skrip, maka bash akan melakukan apa yang Anda harapkan!
Erik Aronesty
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.