通常、スクリプトを編集すると、実行中のスクリプトの使用法はすべてエラーになりがちです。
私が理解している限り、bash(他のシェルも?)はスクリプトを段階的に読み取るため、スクリプトファイルを外部で変更すると、間違ったものを読み取り始めます。それを防ぐ方法はありますか?
例:
sleep 20
echo test
このスクリプトを実行すると、bashは最初の行(たとえば10バイト)を読み取り、スリープ状態になります。再開すると、10バイト目から始まるスクリプトの内容が異なる場合があります。新しいスクリプトの行の途中にいる可能性があります。したがって、実行中のスクリプトは壊れます。
承認された回答:
はいシェル、およびbash
特に、ファイルを一度に1行ずつ読み取るように注意してください。これにより、インタラクティブに使用する場合と同じように機能します。
ファイルが(パイプのように)シークできない場合は、bash
\n
を超えて読み取らないように、一度に1バイトずつ読み取ることもできます。 キャラクター。ファイルがシーク可能である場合、一度に完全なブロックを読み取ることで最適化されますが、\n
の後にシークバックします 。
つまり、次のようなことができます:
bash << \EOF
read var
var's content
echo "$var"
EOF
または、自分自身を更新するスクリプトを作成します。それがあなたにその保証を与えなければ、あなたはそれをすることができなかったでしょう。
さて、あなたがそのようなことをしたいと思うことはめったにありません、そしてあなたが知っているように、その機能はそれが役に立つより頻繁に邪魔になる傾向があります。
これを回避するには、ファイルをインプレースで変更しないようにすることができます(たとえば、コピーを変更して、そのコピーをインプレースに移動します(sed -i
など)。 またはperl -pi
たとえば、一部の編集者はそうします))。
または、次のようにスクリプトを書くこともできます:
{
sleep 20
echo test
}; exit
(exit
が重要であることに注意してください }
と同じ行にある;ただし、閉じる直前のブレースの中に入れることもできます。
または:
main() {
sleep 20
echo test
}
main "[email protected]"; exit
シェルは、exit
までスクリプトを読み取る必要があります 何かを始める前に。これにより、シェルがスクリプトから再度読み取られることがなくなります。
つまり、スクリプト全体がメモリに保存されます。
これは、スクリプトの解析にも影響を与える可能性があります。
たとえば、bash
:
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
UTF-8でエンコードされたU+00E9を出力します。ただし、次のように変更した場合:
{
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
}
\ue9
コマンドが解析されたときに有効だった文字セットで展開されます。この場合は前です。 export
コマンドが実行されます。
source
の場合も注意してください 別名.
コマンドが使用されますが、一部のシェルでは、ソースファイルに対して同じ種類の問題が発生します。
bash
の場合はそうではありません そのsource
コマンドは、ファイルを解釈する前にファイルを完全に読み取ります。 bash
用に作成する場合 具体的には、スクリプトの先頭に次を追加することで、実際にそれを利用できます。
if [[ ! $already_sourced ]]; then
already_sourced=1
source "$0"; exit
fi
(bash
の将来のバージョンを想像できるので、私はそれに依存しません。 現在制限と見なされている動作を変更する可能性があり(bashとAT&T kshは、可能な限りそのように動作する唯一のPOSIXのようなシェルです)、already_sourced
トリックは、変数が環境内にないことを前提としているため、少し脆弱です。もちろん、BASH_SOURCE変数の内容に影響を与えることもあります)