実行中にシェルスクリプトを編集する


91

実行中にシェルスクリプトを編集して、その変更が実行中のスクリプトに影響を与えることはできますか?

バッチがさまざまなビルドフレーバーの束を実行し、一晩実行するcshスクリプトの特定のケースに興味があります。操作中に何かが発生した場合は、そこに行ってコマンドを追加するか、実行されていないコマンドをコメント化します。

できない場合、これを可能にするシェルまたはバッチメカニズムはありますか?

もちろん試してみましたが、うまくいくかどうかがわかるまでには数時間かかります。舞台裏で何が起こっているのか、何が起こっていないのか知りたいです。


1
実行中のスクリプトのスクリプトファイルを編集した結果は2つありました。1)変更が無視されてまるですべてがメモリに読み込まれたか、2)スクリプトがコマンドの一部を読み込んだかのようにエラーでクラッシュします。それがスクリプトのサイズに依存しているかどうかはわかりません。いずれにせよ、私はそれを試しません。
ポールトンブリン

つまり、自己参照/呼び出しでない限り、いいえ。その場合、メインスクリプトは古いスクリプトのままです。
Wrikken、2010

ここで2つの重要な質問があります。1)実行中のスクリプトにコマンドを正しく安全に追加するにはどうすればよいですか?2)実行中のスクリプトを変更するとどうなりますか?
Chris Quenelle 2013年

3
問題は、シェルがスクリプトファイル全体を読み取ってから実行することによってスクリプトを実行するか、それとも実行時に部分的に読み取ることによってスクリプトを実行するかです。どちらなのかわかりません。それも指定されていない場合があります。どちらの動作にも依存しないようにする必要があります。
キーストンプソン

回答:


-67

スクリプトはそのようには機能しません。実行中のコピーは、編集中のソースファイルから独立しています。次にスクリプトを実行するときは、最後に保存されたソースファイルのバージョンに基づいています。

このスクリプトを複数のファイルに分割して、個別に実行するのが賢明な場合があります。これにより、失敗するまでの実行時間が短縮されます。(つまり、バッチを1つのビルドフレーバースクリプトに分割し、それぞれを個別に実行して、問題の原因となっているスクリプトを確認します)。


66
私は反対を観察しました。編集されたbashスクリプトを実行すると、ファイルがbashのスクリプト読み取りファイルの位置に移動するように見えるため、実行中のスクリプトがクラッシュする可能性があります。
Tilman Vogel、

10
複数のシステムでの私の経験では、実行中のコピーはディスクファイルから独立していないため、この問題がシェルスクリプトプログラミングで驚くほど重要です。
Chris Quenelle 2013年

6
これは、オンディスクファイルと無関係ではありません。シェルは通常、たとえば128バイトまたは4096バイトまたは16384バイトのブロックでスクリプトを読み取り、新しい入力が必要な場合にのみ次のブロックを読み取ります。(スクリプトを実行しているシェルでlsofのようなことを実行して、ファイルが開いていることを確認できます。)
mirabilos

5
いいえ。実際、スクリプトを編集すると、プロセスが失敗します。
Erik Aronesty 2013年

8
あなたは正しくありません。これは、実装とスクリプトで呼び出される実際のコマンドに応じてバッファリングされます。stdoutがファイルにリダイレクトされるかどうかに関係なく、多くの要因があり、答えは単純ではありません。
GL2014

50

それ、少なくとも私の環境ではbashに影響を及ぼしますが、非常に不快な方法です。これらのコードを参照してください。最初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."

私の場合、出力は常に次のとおりです。

こんにちは
こんにちは
それで全部です。
それで全部です。

(もちろん、自動化する方がはるかに優れていますが、上記の例は読みやすくなっています。)

[編集]これは予測できないため、危険です。最善の回避策はありここで説明するように ブレースですべてを入れて、閉じ括弧の前に、「終了」を置きますリンクされた回答をよく読んで、落とし穴を避けてください。

[追加]正確な動作は、1つの余分な改行、およびおそらくUnixフレーバー、ファイルシステムなどにも依存します。単に影響を確認したい場合は、単に「echo foo / bar」をb.shの前後に追加します。 「読み取り」行。


3
ええと、愛情はわかりません。何か不足していますか?
ユーザー不明の

正確な動作は、1つの余分な改行、およびおそらくUnixフレーバー、ファイルシステムなどにも依存します。単に影響を確認したい場合は、b.sh10行のecho foo / bar / bazを追加するだけで拡大できます。dave4220と私による答えの要点は、効果を予測するのは容易ではないということです。(ところで名詞「affection」は「愛」を意味します=)
teika kazura

はい、とても壊れています。解決策があります(下記)。さらに危険なのは、svn / rsync / gitの更新です
Erik Aronesty 2013年

39

これを試してください...というファイルを作成しますbash-is-odd.sh

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

これは、bashが実際にスクリプトを「そのまま」解釈していることを示しています。実際、実行時間の長いスクリプトを編集すると、ランダムな文字が挿入されるなど、予期しない結果が生じます。なぜですか?bashは最後のバイト位置から読み取るため、編集すると現在読み取られている文字の位置がシフトします。

つまり、バッシュはこの「機能」のため、非常に安全ではありません。svnとrsyncbashスクリプトで使用すると、デフォルトで結果を「マージ」するので特に厄介です。rsyncこれを修正するモードがあります。svnとgitにはありません。

解決策を提示します。というファイルを作成します/bin/bashx

#!/bin/bash
source "$1"

今すぐ#!/bin/bashxあなたのスクリプトで使用し、常にのbashx代わりにそれらを実行してくださいbash。これは、問題を修正-あなたが安全にできるrsyncスクリプトを。

@ AF7によって提案/テストされた代替(インライン)ソリューション:

{
   # your script
} 
exit $?

中括弧は編集から保護し、終了は追加から保護します。もちろん、bashに-w(ファイル全体)のようなオプション、またはこれを実行するオプションが付属していれば、私たち全員がはるかに良くなるでしょう。


1
ところで; ここに、マイナスに対抗するプラスがあります。編集した答えが好きだからです。
Andrew Barber

1
これはお勧めできません。この回避策では、位置パラメータが1つシフトされます。また、$ 0に値を割り当てることはできません。つまり、単に「/ bin / bash」を「/ bin / bashx」に変更すると、多くのスクリプトが失敗します。
かいらていか2013

1
そのようなオプションはすでに実装されていることを教えてください!
AF7、2015

10
友人のGi​​ulioが私に提案した簡単な解決策(当然のことながらクレジット)は、スクリプトの最初に{を最初に、}を最後に挿入することです。バッシュはメモリ内のすべてを強制的に読み取られます。
AF7 2015

1
@ AF7はあなたの友人のソリューションを改善します:{your_code; } && 出口; 最後に追加された行も実行されなくなります。
korkman

17

スクリプトを関数に分割し、関数が呼び出されるたびsourceに別のファイルからスクリプトを呼び出します。その後、いつでもファイルを編集できます。実行中のスクリプトは、次にソースを取得するときに変更を取得します。

foo() {
  source foo.sh
}
foo

しばらくの間、この手法を効果的に使用して、実行中のビルドスクリプトを実行中に更新しています。現在のファイルをファイルの最後まで読み取るためのテクニックを学びたいので、各シェルスクリプトを実装するために2つのファイルを用意する必要はありません。
Chris Quenelle 2013年

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 2013

2
実際、それはあなたのエディターがあなたが思っているように動かないことを証明しています。多くのエディター(vim、emacsを含む)は、ライブファイルではなく「tmp」ファイルを操作します。vi / emacsの代わりに "echo 'echo uh oh' >> myshell.sh"を使用してみてください。新しいものが出力されるのを見てください。さらに悪いことに、svnとrsyncもこのように編集します!
Erik Aronesty 2013年

3
-1。このエラーは、編集中のファイルとは関係ありません。アポストロフィを使用しているためです。これは単一引用符として機能し、エラーを引き起こします。文字列全体を二重引用符で囲み、再試行してください。
匿名ペンギン

5
エラーが発生したという事実は、編集が意図した効果を持っていなかったことを示しています。
danmcardle 2015年

@danmcardle誰が知っていますか?たぶんバッシュソーChange didn'ned
Kirill Bulygin

1

これがすべて1つのスクリプト内にある場合、機能しません。ただし、サブスクリプトを呼び出すドライバースクリプトとして設定した場合、呼び出される前、またはループしている場合は再度呼び出される前に、サブスクリプトを変更できる可能性があります。実行に反映されます。


0

聞こえません...しかし、いくつかの間接参照についてはどうでしょうか。

BatchRunner.sh

Command1.sh
Command2.sh

Command1.sh

runSomething

Command2.sh

runSomethingElse

次に、BatchRunnerが正しく実行する前に、各コマンドファイルの内容を編集できるはずです。

または

よりクリーンなバージョンでは、BatchRunnerは、一度に1行ずつ連続して実行される単一のファイルを参照します。次に、最初のファイルが正しく実行されている間に、この2番目のファイルを編集できるはずです。


それらを実行するためにメモリにロードし、メインプロセスが開始されたら変更は問題にならないかどうか疑問に思います...
Eric Hodonsky

0

スクリプトの代わりにZshを使用してください。

AFAICT、Zshはこの苛立たしい動作を示しません。


これが、#ashがbashよりも優先される理由473です。私は最近、実行に10分かかる古いbashスクリプトで作業しており、完了するのを待っている間は編集できません!
ミカエリオット

-5

通常、実行中にスクリプトを編集することは一般的ではありません。あなたがしなければならないすべてはあなたの操作のための制御チェックを入れることです。if / elseステートメントを使用して、条件を確認します。何かが失敗した場合は、これを実行し、それ以外の場合はそれを実行します。それは行く方法です。


実際には、操作の途中でバッチジョブを変更することを決定するよりも、スクリプトが失敗することの方が少ないです。コンパイルしたいものがもっとある、またはすでにキューにある特定のジョブを必要としないことをIEが認識している。
ACK

1
スクリプトに厳密に追加すると、bashは期待どおりに動作します。
Erik Aronesty 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.