Edytuj skrypt powłoki, gdy jest uruchomiony

96

Czy możesz edytować skrypt powłoki, gdy jest uruchomiony, i mieć wpływ na zmiany działającego skryptu?

Ciekawi mnie konkretny przypadek skryptu csh, który mam, który uruchamia kilka różnych smaków kompilacji i działa przez całą noc. Jeśli coś przyjdzie mi do głowy w trakcie operacji, chciałbym wejść i dodać dodatkowe polecenia lub zakomentować te, które nie zostały wykonane.

Jeśli nie jest to możliwe, czy istnieje mechanizm powłoki lub wsadowy, który pozwoliłby mi to zrobić?

Oczywiście próbowałem, ale miną godziny, zanim zobaczę, czy zadziałało, czy nie, i jestem ciekaw, co się dzieje, a co nie dzieje się za kulisami.

ACK
źródło
1
Widziałem dwa rezultaty edycji pliku skryptu dla uruchomionego skryptu: 1) zmiany są ignorowane, jakby wczytywał całość do pamięci lub 2) skrypt ulega awarii z błędem, jakby odczytał część polecenia. Nie wiem, czy to zależy od rozmiaru skryptu. Tak czy inaczej, nie próbowałbym tego.
Paul Tomblin
W skrócie: nie, chyba że odwołuje się do siebie / wywołuje, w takim przypadku główny skrypt nadal byłby starym.
Wrikken
Tu są dwa ważne pytania. 1) Jak poprawnie i bezpiecznie dodawać polecenia do uruchomionego skryptu? 2) Kiedy zmodyfikuję uruchomiony skrypt, co się stanie?
Chris Quenelle
3
Pytanie brzmi, czy powłoka wykonuje skrypt, odczytując cały plik skryptu, a następnie go wykonując, czy też częściowo odczytując go podczas wykonywania. Nie wiem, co to jest; może nawet nie zostać określone. Należy unikać uzależnienia od któregokolwiek z tych zachowań.
Keith Thompson,

Odpowiedzi:

-69

Skrypty nie działają w ten sposób; wykonywana kopia jest niezależna od edytowanego pliku źródłowego. Gdy skrypt zostanie uruchomiony następnym razem, będzie oparty na ostatnio zapisanej wersji pliku źródłowego.

Rozsądne może być podzielenie tego skryptu na wiele plików i uruchomienie ich osobno. Skróci to czas wykonywania do awarii. (tj. podziel wsad na jeden skrypt kompilacji, uruchamiając każdy z nich osobno, aby zobaczyć, który z nich powoduje problem).

bród
źródło
68
Zauważyłem coś przeciwnego. Uruchamianie skryptów basha, które są edytowane, może spowodować awarię uruchomionego skryptu, ponieważ plik wydaje się poruszać pod pozycją odczytu skryptu basha.
Tilman Vogel,
10
Z mojego doświadczenia na wielu systemach wynika, że ​​wykonywana kopia NIE jest niezależna od pliku dyskowego, dlatego ten problem jest tak zaskakujący i ważny w programowaniu skryptów powłoki.
Chris Quenelle
6
Na pewno nie jest niezależny od pliku na dysku. Powłoka po prostu czyta skrypty w blokach, na przykład 128 bajtów lub 4096 bajtów lub 16384 bajtów, i odczytuje następny blok tylko wtedy, gdy potrzebuje nowego wejścia. (Możesz zrobić takie rzeczy, jak lsof na powłoce, uruchamiając skrypt i zobaczyć, że plik nadal jest otwarty.)
mirabilos
5
Nie. W rzeczywistości edycja skryptu powoduje niepowodzenie procesu.
Erik Aronesty,
8
Nie masz racji. Jest buforowany w zależności od implementacji i rzeczywistego polecenia wywoływanego w skrypcie, niezależnie od tego, czy stdout jest przekierowywane do pliku, jest wiele czynników, a Twoja odpowiedź nie jest po prostu poprawna.
GL2014
52

Ma to wpływ, przynajmniej uderza w moje otoczenie, ale w bardzo nieprzyjemny sposób . Zobacz te kody. Po pierwsze a.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."

Zrobić

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

W moim przypadku wynik jest zawsze:

Witaj
Witaj
To wszystko.
To wszystko.

(Oczywiście znacznie lepiej jest to zautomatyzować, ale powyższy przykład jest czytelny).

[edytuj] To jest nieprzewidywalne, a więc niebezpieczne. Najlepiej jest obejście , jak opisano tutaj umieścić wszystko w nawias, a przed nawiasem zamykającym, umieścić „exit” . Przeczytaj dobrze połączoną odpowiedź, aby uniknąć pułapek.

[dodano] Dokładne zachowanie zależy od jednej dodatkowej nowej linii i być może także od twojego uniksowego stylu, systemu plików itp. Jeśli po prostu chcesz zobaczyć jakieś wpływy, po prostu dodaj "echo foo / bar" do b.sh przed i / lub po wiersz „czytaj”.

teika kazura
źródło
3
Mh, nie widzę uczucia. Czy coś mi brakuje?
użytkownik nieznany
Dokładne zachowanie zależy od jednej dodatkowej nowej linii i być może także od uniksowego stylu, systemu plików itp., Co do których nie jestem pewien. Jeśli chcesz po prostu zobaczyć jakieś wpływy, po prostu powiększ b.sh, dodając 10 linii echo foo / bar / baz. Istota odpowiedzi udzielonych przez dave4220 i mnie jest taka, że ​​efekt nie jest łatwy do przewidzenia. (BTW rzeczownik "schorzenie" oznacza "miłość" =)
Teika Kazura
tak, jest bardzo zepsuty. mam rozwiązanie (poniżej). jeszcze bardziej niebezpieczne są aktualizacje svn / rsync / git
Erik Aronesty
40

Spróbuj tego ... utwórz plik o nazwie bash-is-odd.sh:

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

To pokazuje, że bash rzeczywiście interpretuje skrypt „na bieżąco”. Rzeczywiście, edycja długo działającego skryptu ma nieprzewidywalne rezultaty, wstawianie losowych znaków itp. Dlaczego? Ponieważ bash czyta od ostatniej pozycji bajtu, więc edycja zmienia położenie aktualnie odczytywanego znaku.

Jednym słowem, Bash jest bardzo, bardzo niebezpieczny z powodu tej „funkcji”. svn i rsyncgdy są używane ze skryptami bash są szczególnie kłopotliwe, ponieważ domyślnie „scalają” wyniki ... edycja na miejscu. rsyncma tryb, który to naprawia. svn i git nie.

Przedstawiam rozwiązanie. Utwórz plik o nazwie /bin/bashx:

#!/bin/bash
source "$1"

Teraz używaj #!/bin/bashxna swoich skryptach i zawsze uruchamiaj je za pomocą bashxzamiast bash. To rozwiązuje problem - możesz bezpiecznie rsyncużywać swoich skryptów.

Alternatywne (in-line) rozwiązanie zaproponowane / przetestowane przez @ AF7:

{
   # your script
} 
exit $?

Nawiasy kręcone chronią przed edycją, a wyjście przed wyrostkami. Oczywiście wszystkim byłoby znacznie lepiej, gdyby bash był wyposażony w opcję, taką jak -w(cały plik) lub coś, co robiło to.

Erik Aronesty
źródło
1
Btw; tutaj jest plus, aby zrównoważyć minus i ponieważ podoba mi się twoja zredagowana odpowiedź.
Andrew Barber
1
Nie mogę tego polecić. W tym obejściu parametry pozycyjne są przesuwane o jeden. Pamiętaj też, że nie możesz przypisać wartości 0 $. Oznacza to, że jeśli po prostu zmienisz „/ bin / bash” na „/ bin / bashx”, wiele skryptów zawiedzie.
teika kazura
1
Proszę powiedz mi, że taka opcja została już wdrożona!
AF7
10
Prostym rozwiązaniem, które zasugerował mi mój przyjaciel Giulio (napisy, gdzie należne) jest wstawienie {na początku i} na końcu zeszytu. Bash jest zmuszony czytać wszystko w pamięci.
AF7,
1
@ AF7 ulepszanie rozwiązania znajomego: {your_code; } && wyjście; zapobiegnie również wykonywaniu wierszy dołączanych na końcu.
korkman
17

Podziel skrypt na funkcje i za każdym razem, gdy zostanie wywołana funkcja, sourcez osobnego pliku. Następnie możesz edytować pliki w dowolnym momencie, a uruchomiony skrypt przyjmie zmiany następnym razem, gdy zostanie pobrany.

foo() {
  source foo.sh
}
foo
glenn jackman
źródło
Od jakiegoś czasu skutecznie używam tej techniki, aby aktualizować moje długo działające skrypty kompilacji podczas ich działania. Chciałbym nauczyć się techniki sprawiania, że ​​bieżący plik będzie czytany do końca, tak żebym nie musiał mieć dwóch plików, aby zaimplementować każdy skrypt powłoki.
Chris Quenelle
3

Dobre pytanie! Mam nadzieję, że ten prosty skrypt pomoże

#!/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"

Wydaje się, że pod Linuksem zmiany dokonane w wykonywanym pliku .sh są wprowadzane przez skrypt wykonawczy, jeśli można pisać wystarczająco szybko!

Will Turner
źródło
2

Interesująca uwaga na marginesie - jeśli uruchamiasz skrypt w Pythonie, to się nie zmienia. (Jest to prawdopodobnie rażąco oczywiste dla każdego, kto rozumie, jak powłoka uruchamia skrypty Pythona, ale pomyślał, że może to być przydatne przypomnienie dla kogoś, kto szuka tej funkcji).

Ja stworzyłem:

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

Następnie w innej powłoce, gdy ten śpi, edytuj ostatnią linię. Po zakończeniu wyświetla niezmienioną linię, prawdopodobnie dlatego, że działa .pyc? To samo dzieje się na Ubuntu i macOS.

Chris
źródło
1

Nie mam zainstalowanego csh, ale

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

Uruchom to, szybko edytuj ostatnią linię do przeczytania

echo Change happened

Wyjście jest

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

Hrmph.

Wydaje mi się, że zmiany w skryptach powłoki nie przynoszą efektu, dopóki nie zostaną ponownie uruchomione.

dave4420
źródło
2
powinieneś umieścić ciąg, który chcesz wyświetlić w cudzysłowie.
user1463308
2
w rzeczywistości dowodzi, że Twój edytor nie działa tak, jak myślisz. wiele, wiele edytorów (w tym vim, emacs) działa na pliku "tmp", a nie na pliku live. Spróbuj użyć "echo 'echo uh oh' >> myshell.sh" zamiast vi / emacs ... i obserwuj, jak wypisuje nowe rzeczy. Gorzej ... svn i rsync również edytują w ten sposób!
Erik Aronesty,
3
-1. Ten błąd nie jest związany z edytowanym plikiem: to dlatego, że używasz apostrofu! To działa jak pojedynczy cytat, powodując błąd. Umieść cały ciąg w cudzysłowie i spróbuj ponownie.
Anonimowy Pingwin
5
Fakt, że wystąpił błąd, wskazuje, że zmiana nie przyniosła zamierzonego efektu.
danmcardle
@danmcardle Kto wie? Może bash widział Change didn'ned.
Kirill Bulygin
1

Jeśli to wszystko jest w jednym skrypcie, to nie, to nie zadziała. Jeśli jednak skonfigurujesz go jako skrypt sterownika wywołujący skrypty podrzędne, możesz być w stanie zmienić skrypt podrzędny przed jego wywołaniem lub przed ponownym wywołaniem, jeśli wykonujesz pętlę, iw takim przypadku wierzę, że te zmiany zostanie odzwierciedlone w wykonaniu.

Ethan Shepherd
źródło
0

Słyszę nie ... ale co z pewnym pośrednim:

BatchRunner.sh

Command1.sh
Command2.sh

Command1.sh

runSomething

Command2.sh

runSomethingElse

Wtedy powinieneś być w stanie edytować zawartość każdego pliku poleceń, zanim BatchRunner przejdzie do niego, prawda?

LUB

Bardziej przejrzysta wersja miałaby wyglądać BatchRunner do pojedynczego pliku, w którym uruchamiałby kolejno po jednej linii na raz. Wtedy powinieneś móc edytować ten drugi plik, gdy pierwszy jest uruchomiony, prawda?

ACK
źródło
Zastanawiam się, czy ładuje je do pamięci, aby je uruchomić, a zmiana nie ma znaczenia po zainicjowaniu głównego procesu ...
Eric Hodonsky
0

Zamiast tego użyj Zsh do tworzenia skryptów.

ODPOWIEDŹ, Zsh nie wykazuje tego frustrującego zachowania.

Micah Elliott
źródło
To jest powód # 473, aby preferować Zsh od bash. Niedawno pracowałem nad starym skryptem basha, którego uruchomienie zajmuje 10 minut i nie mogę go edytować, czekając na zakończenie!
Micah Elliott
-5

zwykle rzadko edytuje się skrypt podczas jego działania. Wszystko, co musisz zrobić, to poddać kontroli swoje operacje. Użyj instrukcji if / else, aby sprawdzić warunki. Jeśli coś się nie powiedzie, zrób to, w przeciwnym razie zrób to. To jest droga do zrobienia.

ghostdog74
źródło
Właściwie mniej chodzi o awarie skryptów, niż o decyzję o modyfikacji zadania wsadowego w trakcie operacji. IE zdaje sobie sprawę, że jest więcej rzeczy, które chcę skompilować, lub że nie potrzebuję pewnych zadań już w kolejce.
potwierdzenie
1
Jeśli ściśle dołączasz do skryptów, bash zrobi to, czego oczekujesz!
Erik Aronesty,