Редагуйте сценарій оболонки під час запуску


91

Чи можете ви редагувати сценарій оболонки під час запуску і чи впливають зміни на запущений сценарій?

Мені цікаво про конкретний випадок скрипта csh, який у мене є, що партія запускає купу різноманітних компонентів збірки і працює всю ніч. Якщо щось мені здається в середині операції, я хотів би зайти і додати додаткові команди, або прокоментувати невиконані.

Якщо це неможливо, чи існує якась оболонка або пакетний механізм, який дозволив би мені це зробити?

Звичайно, я спробував це, але пройде кілька годин, перш ніж я зрозумію, спрацювало це чи ні, і мені цікаво, що відбувається чи не відбувається за лаштунками.


1
Я бачив два результати редагування файлу сценарію для запущеного сценарію: 1) зміни ігноруються так, ніби він прочитав все в пам’яті, або 2) сценарій аварійно завершує роботу, ніби прочитав частину команди. Я не знаю, чи це залежить від розміру сценарію. У будь-якому випадку, я б не спробував.
Пол Томблін,

Коротше кажучи: ні, якщо це не самовідсилання / виклик, в цьому випадку основним сценарієм все одно буде старий.
Wrikken

Тут є два важливих питання. 1) Як я можу правильно та безпечно додати команди до запущеного сценарію? 2) Коли я зміню запущений сценарій, що станеться?
Chris Quenelle

3
Питання полягає в тому, чи виконує оболонка сценарій, читаючи весь файл сценарію, а потім виконуючи його, або частково читаючи його під час виконання. Я не знаю, що це; це може бути навіть не вказано. Слід уникати залежно від поведінки.
Кіт Томпсон,

Відповіді:


-67

Сценарії не працюють таким чином; виконувана копія не залежить від вихідного файлу, який ви редагуєте. Наступного разу, коли сценарій буде запущений, він базуватиметься на останній збереженій версії вихідного файлу.

Було б доцільно розбити цей сценарій на кілька файлів і запустити їх окремо. Це скоротить час виконання до відмови. (тобто розділіть партію на один сценарій створення аромату, запускаючи кожен окремо, щоб побачити, який із них викликає проблеми).


66
Я спостерігав протилежне. Запуск скриптів bash, які редагуються, може призвести до аварійного завершення роботи запущеного сценарію, оскільки файл, здається, рухається під позицією файлу читання сценарію bash.
Тілман Фогель

10
З мого досвіду в багатьох системах, виконувана копія НЕ є незалежною від дискового файлу, тому ця проблема є настільки дивною та важливою при програмуванні сценарію оболонки.
Chris Quenelle

6
Це точно не залежить від файлу на диску. Оболонка зазвичай просто читає сценарії в блоках, наприклад, 128 байтів, 4096 байтів або 16384 байтів, а наступний блок читає лише тоді, коли потрібен новий ввід. (Ви можете робити такі речі, як lsof, на оболонці, на якій запущений сценарій, і побачити, що файл все ще відкрито.)
mirabilos

5
Ні. Насправді, якщо ви редагуєте сценарій, це спричиняє невдачу процесу.
Ерік Аронесті,

8
Ви не праві. Він буферизується залежно від реалізації та фактичної команди, що викликається у сценарії, чи перенаправляється stdout у файл, є багато факторів, і ваша відповідь не просто правильна.
GL2014,

50

Це дійсно впливає, по крайней мере , Баш в моєму оточенні, але дуже неприємно . Див. Ці коди. По-перше 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."

Роби

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

У моєму випадку результат завжди:

Здравствуйте
Здравствуйте
Це все.
Це все.

(Звичайно, набагато краще його автоматизувати, але наведений приклад читається.)

[редагувати] Це непередбачувано, отже небезпечно. Кращим рішенням є , як описано тут , помістити все в дужки і перед закриваючою дужкою, поставити «вихід» . Добре прочитайте відповідну відповідь, щоб уникнути підводних каменів.

[додано] Точна поведінка залежить від одного додаткового нового рядка, а також, можливо, від вашого Unix-аромату, файлової системи тощо. Якщо ви просто хочете побачити деякі впливи, просто додайте "echo foo / bar" до b.sh до та / або після рядок "прочитати".


3
М-м-м, я не бачу прихильності. Мені чогось не вистачає?
невідомий користувач

Точна поведінка залежить від одного додаткового нового рядка , а, можливо, також від Unix-аромату, файлової системи тощо, про що не впевнені в інших. Якщо ви просто хочете побачити будь-який вплив, просто збільште b.sh, додавши 10 рядків echo foo / bar / baz. Суть відповідей dave4220 і мене полягає в тому, що ефект непросто передбачити. (BTW іменник "прихильність" означає "любов" =)
teika kazura

так, це дуже зламано. у мене є рішення (нижче). ще більш небезпечним є оновлення svn / rsync / git
Ерік Аронесті,

39

Спробуйте це ... створити файл із назвою bash-is-odd.sh:

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

Це демонструє, що bash насправді інтерпретує сценарій "по ходу". Дійсно, редагування тривалого сценарію призводить до непередбачуваних результатів, вставки випадкових символів тощо. Чому? Оскільки bash читає з останньої позиції байта, тому редагування зміщує розташування поточного символу, який читається.

Одним словом, Баш дуже, дуже небезпечний через цю "особливість". svn і rsyncпри використанні з bash-сценаріями особливо турбує, оскільки за замовчуванням вони "зливають" результати ... редагування на місці. rsyncмає режим, який це виправляє. svn та git ні.

Я представляю рішення. Створіть файл із назвою /bin/bashx:

#!/bin/bash
source "$1"

Тепер використовуйте #!/bin/bashxна своїх скриптах і завжди запускайте їх bashxзамість bash. Це вирішує проблему - ви можете безпечно використовувати rsyncсвої сценарії.

Альтернативне (вбудоване) рішення, запропоноване / випробуване @ AF7:

{
   # your script
} 
exit $?

Фігурні дужки захищають від редагувань, а вихід захищає від прилипань. Звичайно, нам усім було б набагато краще, якби bash мав опцію, наприклад -w(цілий файл), або щось, що робило це.


1
До речі; ось плюс для протидії мінусу і тому, що мені подобається ваша відредагована відповідь.
Ендрю Барбер

1
Я не можу рекомендувати це. У цьому обхідному шляху позиційні параметри зміщуються на один. Також пам’ятайте, що ви не можете призначити значення $ 0. Це означає, що якщо ви просто зміните "/ bin / bash" на "/ bin / bashx", багато сценаріїв не вдаються.
teika kazura

1
Скажіть, будь ласка, що такий варіант вже реалізований!
AF7

10
Просте рішення, запропоноване мені моїм другом Джуліо (кредити, де потрібно), - це вставити {на початку та} в кінці фрагмента. Баш змушений читати все в пам'яті.
AF7,

1
@ AF7 вдосконалення рішення вашого друга: {your_code; } && вихід; також запобіжить виконанню рядків, доданих до кінця.
korkman

17

Розбийте свій скрипт на функції, і кожен раз, коли функція викликається вам sourceіз окремого файлу. Тоді ви можете будь-коли редагувати файли, і ваш запущений сценарій забере зміни наступного разу, коли він отримає джерело.

foo() {
  source foo.sh
}
foo

Я вже деякий час ефективно використовую цю техніку для оновлення своїх тривалих сценаріїв збірки під час роботи. Я хотів би навчитися техніці змушення читати поточний файл до кінця файлу, так що мені не потрібно мати два файли для реалізації кожного сценарію оболонки.
Chris Quenelle

3

Гарне питання! Сподіваюся, цей простий сценарій допоможе

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

Здається, під Linux, що зміни, внесені до виконуваного .sh, виконуються виконуючим сценарієм, якщо ви можете вводити досить швидко!


2

Цікава побічна примітка - якщо у вас запущений сценарій Python, він не змінюється. (Це, мабуть, очевидно очевидно для кожного, хто розуміє, як оболонка запускає скрипти Python, але вважав, що це може бути корисним нагадуванням для тих, хто шукає цю функціональність.)

Я створив:

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

Потім в іншій оболонці, поки вона спить, відредагуйте останній рядок. Коли це завершується, відображається незмінений рядок, можливо, тому, що на ньому запущено .pyc? Те саме відбувається в Ubuntu та macOS.


1

У мене не встановлено csh, але

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

Запустіть це, швидко відредагуйте останній рядок для читання

echo Change happened

Вихід є

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

Хрмм.

Думаю, редагування сценаріїв оболонки не набувають чинності, поки їх не буде повторено.


2
слід помістити рядок, який потрібно відобразити в лапках.
user1463308

2
насправді, це доводить, що ваш редактор працює не так, як ви думаєте. багато, багато редакторів (включаючи vim, emacs) працюють із файлом "tmp", а не з реальним файлом. Спробуйте використати "echo 'echo uh oh' >> myshell.sh" замість vi / emacs ... і спостерігайте, як він видає нові матеріали. Гірше ... svn та rsync також редагують таким чином!
Ерік Аронесті,

3
-1. Ця помилка не пов’язана з файлом, що редагується: це тому, що ви використовуєте апостроф! Це діє як одна лапка, що спричиняє помилку. Помістіть цілий рядок у подвійні лапки та спробуйте ще раз.
Анонімний пінгвін

5
Той факт, що сталася помилка, свідчить про те, що редагування не мало передбачуваного ефекту.
danmcardle

@danmcardle Хто знає? Можливо, Баш бачив Change didn'ned.
Кирило Булигін

1

Якщо це все в одному сценарії, то ні, це не спрацює. Однак, якщо ви встановите його як скрипт драйвера, який викликає підскрипти, ви можете змінити підкрипт до того, як він буде викликаний, або перед тим, як він буде викликаний знову, якщо ви циклічно повторюєте, і в цьому випадку я вірю, що ці зміни буде відображено у виконанні.


0

Я не чую ... але як щодо певної непрямості:

BatchRunner.sh

Command1.sh
Command2.sh

Command1.sh

runSomething

Command2.sh

runSomethingElse

Тоді ви зможете редагувати вміст кожного командного файлу до того, як BatchRunner дістанеться до нього правильно?

АБО

Чистіша версія BatchRunner переглядає один файл, де послідовно запускається по одному рядку. Тоді ви повинні мати можливість редагувати цей другий файл, поки перший працює правильно?


Цікаво, чи завантажує їх у пам’ять для їх запуску, і зміна не має значення, як тільки розпочнеться основний процес ...
Ерік Ходонський

0

Замість цього використовуйте Zsh для сценаріїв.

AFAICT, Zsh не виявляє цієї неприємної поведінки.


Це причина # 473 віддавати перевагу Zsh башу. Нещодавно я працював над старим сценарієм bash, який займає 10 м, і я не можу його редагувати, чекаючи його завершення!
Міка Елліот

-5

зазвичай нечасто редагувати скрипт під час його роботи. Все, що вам потрібно зробити, це встановити контрольний чек ваших операцій. Використовуйте оператори if / else, щоб перевірити умови. Якщо щось не вдається, зробіть це, інакше зробіть те. Це шлях.


Насправді це менше про невдачі сценаріїв, ніж про те, щоб вирішити змінити пакетну роботу в середині операції. IE усвідомлюючи, що я хочу скомпілювати більше, або що мені не потрібні певні роботи, які вже в черзі.
ack

1
Якщо ви строго додаєте сценарії, тоді bash зробить те, що ви очікуєте!
Ерік Аронесті,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.