Редактировать сценарий оболочки во время его работы

95

Можете ли вы отредактировать сценарий оболочки во время его работы, чтобы изменения повлияли на работающий сценарий?

Мне любопытен конкретный случай csh-скрипта, который у меня есть, эта партия запускает кучу различных вариантов сборки и работает всю ночь. Если что-то случится со мной в середине операции, я бы хотел войти и добавить дополнительные команды или закомментировать невыполненные.

Если это невозможно, есть ли какая-нибудь оболочка или пакетный механизм, который позволил бы мне это сделать?

Конечно, я пробовал, но пройдут часы, прежде чем я увижу, сработало это или нет, и мне любопытно, что происходит или не происходит за кулисами.

подтверждать
источник
1
Я видел два результата редактирования файла сценария для запущенного сценария: 1) изменения игнорируются, как если бы он считал все это в память, или 2) сценарий вылетает с ошибкой, как если бы он прочитал часть команды. Я не знаю, зависит ли это от размера сценария. В любом случае, я бы не стал пробовать.
Пол Томблин,
Вкратце: нет, если только он не ссылается на себя / вызывается, и в этом случае основным скриптом все равно будет старый.
Wrikken 03
Здесь есть два важных вопроса. 1) Как правильно и безопасно добавлять команды в работающий скрипт? 2) Что произойдет, когда я изменю запущенный скрипт?
Chris Quenelle
3
Вопрос в том, выполняет ли оболочка сценарий, читая весь файл сценария и затем выполняя его, или частично считывая его во время выполнения. Я не знаю, что это такое; это может даже не указываться. Вам следует избегать зависимости от любого поведения.
Кейт Томпсон,

Ответы:

-68

Скрипты так не работают; исполняемая копия не зависит от исходного файла, который вы редактируете. В следующий раз, когда сценарий будет запущен, он будет основан на последней сохраненной версии исходного файла.

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

форд
источник
68
Я заметил обратное. Выполнение редактируемых сценариев bash может привести к сбою работающего сценария, поскольку файл кажется перемещенным под позицию файла чтения сценария bash.
Tilman Vogel
10
По моему опыту работы с несколькими системами, исполняемая копия НЕ независима от файла на диске, поэтому эта проблема так удивительна и важна при программировании сценариев оболочки.
Chris Quenelle
6
Это определенно не зависит от файла на диске. Оболочка обычно читает сценарии блоками, например, по 128 или 4096 байтов или 16384 байта, и читает следующий блок только тогда, когда ему нужен новый ввод. (Вы можете делать такие вещи, как lsof в оболочке, запускающей скрипт, и видеть, что файл все еще открыт.)
mirabilos
5
Нет. На самом деле, если вы редактируете сценарий, это приводит к сбою процесса.
Эрик Аронести
8
Вы не правы. Он буферизуется в зависимости от реализации и фактической команды, вызываемой в сценарии, перенаправляется ли стандартный вывод в файл, существует множество факторов, и ваш ответ не просто правильный.
GL2014, 03
51

Это действительно влияет, по крайней мере, на удар в моем окружении, но очень неприятным образом . Смотрите эти коды. Первый 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
Ммм, я не вижу привязанности. Я что-то упускаю?
user unknown
Точное поведение зависит от одной дополнительной новой строки и, возможно, также от вкуса Unix, файловой системы и т.д., хотя я вообще не уверен. Если вы просто хотите увидеть какие-либо влияния, просто увеличьте b.sh, добавив 10 строк echo foo / bar / baz. Суть ответов dave4220 и меня в том, что эффект предсказать непросто. (Кстати, существительное «привязанность» означает «любовь» =)
тейка казура
да, он очень сломан. у меня есть решение (ниже). что еще более опасно, так это обновления svn / rsync / git
Эрик Аронести
40

Попробуйте это ... создайте файл с именем bash-is-odd.sh:

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

Это демонстрирует, что bash действительно интерпретирует сценарий «по ходу». Действительно, редактирование долго работающего скрипта приводит к непредсказуемым результатам, вставке случайных символов и т. Д. Почему? Поскольку bash читает с последней позиции байта, редактирование смещает местоположение текущего читаемого символа.

Одним словом, Bash очень и очень небезопасен из-за этой «особенности». svn и rsyncпри использовании со сценариями bash вызывают особые проблемы, потому что по умолчанию они "объединяют" результаты ... редактирование на месте. rsyncесть режим, который это исправляет. svn и git не работают.

Предлагаю решение. Создайте файл с именем /bin/bashx:

#!/bin/bash
source "$1"

Теперь с помощью #!/bin/bashxваших скриптов и всегда запускать их с bashxвместо bash. Это решает проблему - вы можете безопасно использовать rsyncсвои скрипты.

Альтернативное (линейное) решение, предложенное / протестированное @ AF7:

{
   # your script
} 
exit $?

Фигурные скобки защищают от редактирования, а exit защищает от добавлений. Конечно, нам всем было бы намного лучше, если бы в bash была опция, например -w(весь файл) или что-то подобное.

Эрик Аронести
источник
1
Кстати; вот плюс, чтобы противостоять минусу, и потому что мне нравится ваш отредактированный ответ.
Эндрю Барбер,
1
Я не могу этого рекомендовать. В этом обходном пути позиционные параметры сдвигаются на единицу. Также помните, что вы не можете присвоить значение 0. Это означает, что если вы просто измените «/ bin / bash» на «/ bin / bashx», многие сценарии не работают.
тейка казура
1
Подскажите пожалуйста, что такая опция уже реализована!
AF7
10
Простое решение, предложенное мне моим другом Джулио (примечательно), состоит в том, чтобы вставить {в начале и} в конец сценария. Bash вынужден читать все в памяти.
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

Хмф.

Я предполагаю, что изменения в сценариях оболочки не вступят в силу, пока они не будут перезапущены.

dave4420
источник
2
вы должны заключить строку, которую хотите отобразить, в кавычки.
user1463308
2
фактически, это доказывает, что ваш редактор работает не так, как вы думаете. многие, многие редакторы (включая vim, emacs) работают с файлом "tmp", а не с живым файлом. Попробуйте использовать "echo 'echo uh oh' >> myshell.sh" вместо vi / emacs ... и посмотрите, как он выводит новый материал. Хуже того ... svn и rsync тоже редактируют таким образом!
Эрик Аронести,
3
-1. Эта ошибка не связана с редактируемым файлом: это потому, что вы используете апостроф! Это действует как одинарная кавычка, вызывая ошибку. Поместите всю строку в двойные кавычки и повторите попытку.
Anonymous Penguin
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. Недавно я работал над старым сценарием bash, выполнение которого занимает 10 минут, и я не могу редактировать его, пока он не завершится!
Мика Эллиотт,
-5

обычно редактировать скрипт во время его работы - редкость. Все, что вам нужно сделать, это поставить контроль над своими операциями. Используйте операторы if / else для проверки условий. Если что-то не получится, то сделайте это, иначе сделайте то. Это путь.

призрачная собака74
источник
На самом деле речь идет не столько о сбое сценариев, сколько о решении изменить пакетное задание в середине операции. IE понимает, что есть еще что-то, что я хочу скомпилировать, или что мне не нужны определенные задания, уже стоящие в очереди.
ack
1
Если вы строго добавляете скрипты, то bash сделает то, что вы ожидаете!
Эрик Аронести