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

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

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

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

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


person ack    schedule 03.08.2010    source источник
comment
Я видел два результата редактирования файла сценария для работающего сценария: 1) изменения игнорируются, как если бы он прочитал все это в память, или 2) сценарий вылетает с ошибкой, как если бы он прочитал часть команды. Я не знаю, зависит ли это от размера сценария. В любом случае, я бы не стал пробовать.   -  person Paul Tomblin    schedule 03.08.2010
comment
Вкратце: нет, если только он не является самореферентным/вызывающим, и в этом случае основной сценарий все равно будет старым.   -  person Wrikken    schedule 03.08.2010
comment
Здесь есть два важных вопроса. 1) Как правильно и безопасно добавлять команды в работающий скрипт? 2) Что произойдет, когда я изменю работающий скрипт?   -  person Chris Quenelle    schedule 18.06.2013
comment
Вопрос заключается в том, выполняет ли оболочка сценарий, читая весь файл сценария и затем выполняя его, или частично читая его во время выполнения. Я не знаю, что это такое; это может быть даже не указано. Вы должны избегать зависимости от любого поведения.   -  person Keith Thompson    schedule 25.08.2013


Ответы (11)


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

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

person ford    schedule 03.08.2010
comment
Я наблюдал то же самое. Любое место в документации bash (или csh или ksh), где это упоминается? - person Xolve; 27.06.2011
comment
Я наблюдал обратное. Запуск сценариев bash, которые редактируются, может привести к сбою работающего сценария, потому что файл, кажется, перемещается под позицию чтения файла сценария bash. - person Tilman Vogel; 09.01.2012
comment
По моему опыту работы с несколькими системами, исполняемая копия НЕ является независимой от файла на диске, поэтому эта проблема так удивительна и важна при программировании сценариев оболочки. - person Chris Quenelle; 18.06.2013
comment
Это определенно не независимо от файла на диске. Оболочка обычно просто считывает сценарии блоками, например, по 128 байт, 4096 байт или 16384 байт, и считывает следующий блок только тогда, когда ей требуется новый ввод. (Вы можете делать такие вещи, как lsof в оболочке, выполняющей скрипт, и видеть, что файл все еще открыт.) - person mirabilos; 17.09.2013
comment
Нет. На самом деле, если вы редактируете сценарий, это приводит к сбою процесса. - person Erik Aronesty; 17.10.2013
comment
Вы не правы. Он буферизуется в зависимости от реализации и фактической команды, вызываемой в сценарии, перенаправляется ли стандартный вывод в файл, существует множество факторов, и ваш ответ не просто правильный. - person GL2014; 03.03.2016
comment
@ford - возможно, это то, что вы заметили, но я подозреваю, что это отвлекающий маневр, подброшенный вашим редактором, который может создавать новый файл и перемещать его на место при каждом сохранении, а не редактировать файл напрямую. - person Attie; 30.05.2018
comment
Эти отрицательные голоса отстой. Я не ошибаюсь. Это то, что я наблюдал — так что, если я вижу лицо на Луне, значит ли это, что на Луне действительно есть человек? Мои наблюдения могут быть ошибочными... как и ваши. - person Mark; 19.11.2018

Это действительно влияет, по крайней мере, на мою среду, но очень неприятно. Смотрите эти коды. Первый 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."

Do

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

В моем случае вывод всегда:

hello
hello
That's all.
That's all.

(Конечно, гораздо лучше автоматизировать это, но приведенный выше пример читабелен.)

[править] Это непредсказуемо, поэтому опасно. Лучший обходной путь , как описано здесь заключить все в скобки, а перед закрывающая фигурная скобка, поставить "выход". Внимательно прочитайте связанный ответ, чтобы избежать ошибок.

[добавлено] Точное поведение зависит от одной дополнительной новой строки и, возможно, от вашего варианта Unix, файловой системы и т. д. Если вы просто хотите увидеть некоторые влияния, просто добавьте «echo foo/bar» в b.sh до и/или после строка «прочитано».

person teika kazura    schedule 10.06.2011
comment
Ммм, я не вижу привязанности. Я что-то упускаю? - person user unknown; 17.01.2012
comment
Точное поведение зависит от одного дополнительного символа новой строки и, возможно, также от разновидности Unix, файловой системы и т. д., но я не совсем уверен. Если вы просто хотите увидеть какие-либо влияния, просто увеличьте b.sh, добавив 10 строк echo foo/bar/baz. Суть ответов dave4220 и меня в том, что эффект предсказать непросто. (Кстати, существительное «привязанность» означает любовь =) - person teika kazura; 20.01.2012
comment
да, очень сломан. у меня есть решение (ниже). что еще более опасно, так это обновления svn/rsync/git - person Erik Aronesty; 18.10.2013

Попробуйте это... создайте файл с именем 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 $?
} 

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

person Erik Aronesty    schedule 17.10.2013
comment
Кстати; вот плюс, чтобы противостоять минусу, и потому что мне нравится ваш отредактированный ответ. - person Andrew Barber; 18.10.2013
comment
Я не могу рекомендовать это. В этом обходном пути позиционные параметры сдвигаются на единицу. Также помните, что вы не можете присвоить значение $0. Это означает, что если вы просто измените /bin/bash на /bin/bashx, многие скрипты завершатся ошибкой. - person teika kazura; 21.12.2013
comment
Подскажите пожалуйста, такая возможность уже реализована! - person AF7; 13.07.2015
comment
Простое решение, предложенное мне моим другом Джулио (спасибо, где это необходимо), состоит в том, чтобы вставить { в начале и } в конце скрипта. Bash вынужден читать все в памяти. - person AF7; 14.07.2015
comment
@AF7 улучшает решение вашего друга: { your_code; } && выход; также предотвратит выполнение строк, добавленных в конец. - person korkman; 15.09.2016
comment
Добавление еще || exit также ловит ожидающие коды состояния › 0 :-) - person korkman; 15.09.2016
comment
Я предполагаю, что технически это было бы лучше в качестве ответа на противоположный вопрос (как предотвратить редактирование, влияющее на работающий скрипт), но сейчас это не имеет большого значения. - person David Z; 04.04.2018
comment
@teikakazura не меняет параметр - потому что вы используете исходный код, но он меняет первый аргумент на bashx вместо bash - person Erik Aronesty; 23.04.2020
comment
@ErikAronesty да, rsync редактирует байты с помощью --in-place, но это не меняет проблемы с bash. bash имеет указатель байта, до которого выполнялся скрипт. редактирование сдвига кода за его пределы или добавление кода после этой точки будет выполнено, если только bash не нужно было упреждать код в фигурных скобках, и если этот код является автономным с выходом внутри фигурных скобок, ничто не может быть отредактировано. Я написал } && выход; тогда, сегодня я бы написал выход; } - person korkman; 30.04.2020
comment
@korkman да, я согласен, поэтому bashx точно решает проблему, но такие решения, как {...}; exit $?, потенциально могут иметь гонку, когда файл редактируется между кодом (что безопасно) и командой выхода (что не так). Я думаю, что вы должны поместить выход в фигурные скобки, чтобы быть уверенным. - person Erik Aronesty; 06.05.2020
comment
@ErikAronesty Это правильно, и я имел в виду «сегодня я бы написал выход; }'. Я думаю, вам следует отредактировать свой ответ, тогда :-) - person korkman; 07.05.2020

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

foo() {
  source foo.sh
}
foo
person glenn jackman    schedule 03.08.2010
comment
Я уже некоторое время эффективно использую эту технику для обновления моих долго выполняющихся сценариев сборки во время их работы. Я хотел бы изучить технику чтения текущего файла до конца файла, чтобы мне не приходилось иметь два файла для реализации каждого сценария оболочки. - person Chris Quenelle; 18.06.2013

Хороший вопрос! Надеюсь, этот простой скрипт поможет

#!/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, вступают в силу исполняемым сценарием, если вы можете печатать достаточно быстро!

person Will Turner    schedule 06.09.2018

Интересное примечание: если вы запускаете скрипт Python, он не меняется. (Вероятно, это совершенно очевидно для любого, кто понимает, как оболочка запускает скрипты Python, но подумал, что это может быть полезным напоминанием для тех, кто ищет эту функциональность.)

Я создал:

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

Затем в другой оболочке, пока она спит, отредактируйте последнюю строку. Когда это завершается, отображается неизмененная строка, предположительно потому, что выполняется .pyc? То же самое происходит в Ubuntu и macOS.

person Chris    schedule 09.11.2018

У меня не установлен 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

Хрмф.

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

person dave4420    schedule 03.08.2010
comment
вы должны поместить строку, которую хотите отобразить, в кавычки. - person user1463308; 31.07.2013
comment
на самом деле это доказывает, что ваш редактор работает не так, как вы думаете. многие, многие редакторы (включая vim, emacs) работают с файлом tmp, а не с живым файлом. Попробуйте использовать echo 'echo uh oh' ›› myshell.sh вместо vi/emacs... и посмотрите, как он выводит новые данные. Хуже того... svn и rsync тоже редактируют таким образом! - person Erik Aronesty; 18.10.2013
comment
-1. Эта ошибка не связана с редактируемым файлом: это потому, что вы используете апостроф! Это действует как одинарная кавычка, вызывая ошибку. Поместите всю эту строку в двойные кавычки и повторите попытку. - person Anonymous Penguin; 07.03.2015
comment
Тот факт, что произошла ошибка, показывает, что редактирование не имело ожидаемого эффекта. - person danmcardle; 30.10.2015
comment
@danmcardle Кто знает? Может быть, Баш увидел Change didn'ned. - person Kirill Bulygin; 28.04.2018

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

person Ethan Shepherd    schedule 03.08.2010

Я слышу нет... но как насчет косвенности:

BatchRunner.sh

Command1.sh
Command2.sh

Command1.sh

runSomething

Command2.sh

runSomethingElse

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

ИЛИ

В более чистой версии BatchRunner просматривал бы один файл, где он последовательно запускал бы одну строку за раз. Тогда вы должны иметь возможность редактировать этот второй файл, пока работает первый, верно?

person ack    schedule 03.08.2010
comment
Интересно, загружает ли он их в память для их запуска, и изменение не имеет значения после запуска основного процесса... - person Eric Hodonsky; 22.10.2017

Вместо этого используйте Zsh для своих сценариев.

AFAICT, Zsh не демонстрирует такого разочаровывающего поведения.

person Micah Elliott    schedule 31.03.2020
comment
Это причина № 473 предпочесть Zsh bash. Недавно я работал над старым сценарием bash, для запуска которого требуется 10 м, и я не могу редактировать его, ожидая его завершения! - person Micah Elliott; 01.04.2020

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

person ghostdog74    schedule 03.08.2010
comment
На самом деле речь идет не столько о сбое сценариев, сколько о решении изменить пакетное задание в середине операции. т.е. понимая, что есть еще что-то, что я хочу скомпилировать, или что мне не нужны определенные задания, уже находящиеся в очереди. - person ack; 03.08.2010
comment
Если вы строго добавляете скрипты, то bash будет делать то, что вы ожидаете! - person Erik Aronesty; 18.10.2013