アカウント名:
パスワード:
てっきり最初にスクリプト全部読み込んでから走らせてると思ってた。
京大での事故で広く知られたように、シェルは最初にスクリプト全体を読み込むのではなく、「1行ずつ順次読み込む。そしてスクリプト終端に達したり exit や致命的エラーなどによりスクリプトは終了する。
走らせているスクリプトを変更する機会は今までになかった。期待どおりに動いていないのがわかったらkillしてから書き換えてるし。それでも、本番で長時間走らせている時に不具合見つかったらやっちゃうのかな。
スクリプトを改変するときはバックアップ後に別名コピーしてテストして問題がなければ元の名前に上書きしてた。小手先処理の簡単なスクリプトしか作らないので、バージョン管理とかその手のことはやってない現場仕事ですが。ループがあっても小さいものだし、それくらいなら最初に全部読み込まれそう。
いろいろなパターンがあって難しい...
bash スクリプトの実行中上書き動作についてhttps://zenn.dev/mattn/articles/5af86b61004bdc [zenn.dev]
シェルスクリプトの実行中に間違いに気づき、実行終了を待てなくて編集を始めてしまい、ついいつもの癖で書き込みしてしまって異常終了という経験があり、最初にスクリプトを全部読んでいないということに気づきました。そのとき/bin/bash -x scriptでデバッグしているときは書き込んでも問題が発生しないのに、scriptを単独で動かしているときは問題が発生するのも経験し、/bin/bash でスクリプト指定した場合は最初に全部読んでいるという違いがあることも知りました。また、vimとviでも違いがあり、(本当
Windowsのbatファイルも同じ感じだよね。↓みたいなの書いてpause中にファイル編集してみるとわかる。
echo 1pauseecho 2pauseecho 3pauseecho 4
echo 1pauseecho 2pause
となっているとき、1回目の pause 時に1行目を「echo ABCDEFGHIJKLMNOPQRSTUVWXYZ」に書き換えたら、「'KLMNOPQRSTUVWXYZ' は、内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません。」ってエラーメッセージを出した。なるほど、「pause(CR)(LF)」の次の位置を憶えていてそこから再開しようとするのか。
覚え違えかもだけど、すごい昔の日本語DOSか、MS-DOSか、PC-DOSかCP/Mだかはメモリに読み込んでた記憶があるような。BATが入ったフロッピーディスクを途中で入れ替えする事が有るからメモリにある程度バッファリングしてたのかな。
現在のBATは実行中に書き換えると、上記のようにファイルポインタ位置でずれて意図しない現象が起きるので危険です。
1driveマシンもあったので、FDD入れ替えはありましたね
昔のMS-DOSというと
COPY *.TXT HOGE.TXT
でファイル破壊する仕様があったような……。HOGE.TXTがあると上書きを始めちゃうから、ワイルドカードの展開でHOGE.TXTの番になったところでMS-DOSができないことを検出してエラーで止めるものの、その時点でHOGE.TXTの中身は破壊されているという
今は「一時ファイルを作って最後にHOGE.TXTに上書きする」みたいな処理にして回避してそう
MS-DOSすっかり忘れたcat *.TXT >> HOGE.TXTでよさげ
MS-DOSでテキストを表示するのはcatではなく TYPE コマンドですよ。さらに、COMMAND.COM のTYPEコマンドはワイルドカードに対応してないので、 TYPE *.TXT はできません
PowershellでHOGE.TXTがある状態で
Get-Content *.TXT >> .\HOGE.TXT
を実行すると、無限ループになってHOGE.TXTが際限なく大きくなる。期待通りの動作であって、これをバグとは言わないと思う。ちなみに、
Copy-Item *.TXT .\HOGE.TXT
だと、ワイルドカード展開の順番でHOGE.TXTが来た時にエラーになる。HOGE.TXTの内容は、HOGE.TXTが最初に展開されれば変更されないし、そうでなければ、その直前に展開されたファイルの中身と同じになる。これも期待通りの動作。MS-DOSだと何か違う動作になったのかな?
それはそもそもどんな動作を期待して実行するコマンドなんだ……コピー先見て勝手にコピー順を変えたり一時ファイル生成されるのも迷惑だし、逐次実行してってエラー出たら止まりってのは至極普通の動作だろ。君はエラー時にロールバック(操作前の状態を維持)してほしいかもしれんけど出来たところまででも結果がほしい、エラー時の状態を知りたいってパターンもある。シェルに概ねお任せするGUIならともかく、コマンドなら愚直に実行してくれたほうが有り難いと思う。気配りしたいなら自分でそういうコマンド列ないしはバッチ書いて好きに制御すべし。# その意味ではファイル名等のエスケープ関連こそ批難すべき挙動だと思う。
当時のやつは、CONFIG.SYSのBUFFERSの設定によると思います。BUFFERSにそれなりの大きな値を設定してたらフロッピー上のバッチファイルも一度に読み込みますが、BUFFERS=1とかだとカッチンカッチンと…。
SUBMIT hoge.SUBなんてものもありましたな
(*´ω`*)
上書きじゃなくてmvしよう。
はい、仰せの通りに mv しています
スクリプト書き換えるときは同じdirectoryでやるからファイルシステムマタギは安全そう。
自明かと思って注意しなかった。renameシステムコールを使おう、ならあってる?
あとはemacs使えとか。vimはどうかな?
こうレベルの話だと、「emacsやvimで本番環境のファイルを直接編集する」時点でアウトじゃないですかね。「あらかじめテスト環境で動作確認を取ってから、本番環境に上げる」ようにしないと。
となると、ファイル更新に使うツールはscpとかrsyncとかだけど、自分がやるなら、「別ディレクトリにアップしておいてから、rename(mv)」かな。
実行中書き換えの問題がなくても、「ファイルコピー中の、中途半端な状態のファイルで実行してしまう」リスクが怖いので、ファイルを用意してからatomicに切り替えるようにすべき。
アトミックな置換は大賛成。だけど、実行中だとアトミックに置換しても逐次読みや別ファイル参照で整合性が失われるから、実行中の変更を安全に行うのは基本的には不可能だと思ったほうがいいのよな。
Windowsのアップデートが再起動祭りな事に対してLinuxはアップデートでの再起動をあまり要求しないって誇る人たちが昔は目に付いたけど、逐次読み、別ファイル参照を考慮するとどっちもどっちっていうね。
remove(unlink)じゃね?openして上書きするのが問題なんであって、消してコピーか、renameで内部的にunlinkすれば安全と。unlinkさえしてあれば再オープン出来ないから安全になる。さらにrenameならunlink含めてアトミックだからさらに安心ってことで。
処理系やバージョンによるので確かめてからやりましょうが正解では。
これを故意に使ったのが自己書き換えプログラムなのでは。自分では使ったことないけど。
広義にはそう言えるかもしれないけど、こういうのはタレコミのソースにもあるように「自己追記」とでも呼ぶべきものであって「自己書き換え」とは言わないすね
そのあたりは処理系の作り方に依存するわけで、うちが今使ってるインタープリタの処理が遅いシミュレーションツールは実行中にソースを消去しても何の問題もなくプログラムの実行が続く処理系の中身がどうなってるか知らなくも気軽にプログラミング出来るのは良い時代だが、利用者が中の仕組みをまったく意識しないというのも困る
逐次読み込みするにしてもシェル側でファイルハンドル握って排他制御くらいしろよと思った。
UNIX系のファイルシステムなら、ロックしててもmvでファイル入れ替え可能です。inodeでファイルの実体を管理しているので、名前を変えたり削除しても、ファイル名からの参照ができなくなるだけで実体は残っており、すでにオープンしているファイルハンドルからはそのまま元ファイルにアクセスし続けられます。
ファイルハンドルを保持せず、都度オープンするような実装だと新ファイルにアクセスすることになりますが、その場合は「mvコマンドで安全にファイルを入れ替えて」もアウト。バッチファイルはそういう挙動だったかと思います。
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
Stay hungry, Stay foolish. -- Steven Paul Jobs
しらんかった (スコア:5, 参考になる)
てっきり最初にスクリプト全部読み込んでから走らせてると思ってた。
京大での事故で広く知られたように、シェルは最初にスクリプト全体を読み込むのではなく、「1行ずつ順次読み込む。そしてスクリプト終端に達したり exit や致命的エラーなどによりスクリプトは終了する。
走らせているスクリプトを変更する機会は今までになかった。
期待どおりに動いていないのがわかったらkillしてから書き換えてるし。
それでも、本番で長時間走らせている時に不具合見つかったらやっちゃうのかな。
スクリプトを改変するときはバックアップ後に別名コピーしてテストして問題がなければ元の名前に上書きしてた。
小手先処理の簡単なスクリプトしか作らないので、バージョン管理とかその手のことはやってない現場仕事ですが。
ループがあっても小さいものだし、それくらいなら最初に全部読み込まれそう。
Re:しらんかった (スコア:5, 参考になる)
いろいろなパターンがあって難しい...
bash スクリプトの実行中上書き動作について
https://zenn.dev/mattn/articles/5af86b61004bdc [zenn.dev]
Re: (スコア:0)
シェルスクリプトの実行中に間違いに気づき、実行終了を待てなくて編集を始めてしまい、ついいつもの癖で書き込みしてしまって異常終了という経験があり、最初にスクリプトを全部読んでいないということに気づきました。そのとき
/bin/bash -x script
でデバッグしているときは書き込んでも問題が発生しないのに、scriptを単独で動かしているときは問題が発生するのも経験し、/bin/bash でスクリプト指定した場合は最初に全部読んでいるという違いがあることも知りました。
また、vimとviでも違いがあり、(本当
Re:しらんかった (スコア:1)
Windowsのbatファイルも同じ感じだよね。
↓みたいなの書いてpause中にファイル編集してみるとわかる。
echo 1
pause
echo 2
pause
echo 3
pause
echo 4
Re:しらんかった (スコア:1)
echo 1
pause
echo 2
pause
となっているとき、1回目の pause 時に1行目を「echo ABCDEFGHIJKLMNOPQRSTUVWXYZ」に書き換えたら、
「'KLMNOPQRSTUVWXYZ' は、内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません。」
ってエラーメッセージを出した。
なるほど、「pause(CR)(LF)」の次の位置を憶えていてそこから再開しようとするのか。
Re: (スコア:0)
覚え違えかもだけど、すごい昔の日本語DOSか、MS-DOSか、PC-DOSかCP/Mだかはメモリに読み込んでた記憶があるような。
BATが入ったフロッピーディスクを途中で入れ替えする事が有るからメモリにある程度バッファリングしてたのかな。
現在のBATは実行中に書き換えると、上記のようにファイルポインタ位置でずれて意図しない現象が起きるので危険です。
Re: (スコア:0)
1driveマシンもあったので、FDD入れ替えはありましたね
Re: (スコア:0)
昔のMS-DOSというと
COPY *.TXT HOGE.TXT
でファイル破壊する仕様があったような……。
HOGE.TXTがあると上書きを始めちゃうから、ワイルドカードの展開でHOGE.TXTの番になったところで
MS-DOSができないことを検出してエラーで止めるものの、その時点でHOGE.TXTの中身は破壊されているという
今は「一時ファイルを作って最後にHOGE.TXTに上書きする」みたいな処理にして回避してそう
Re: (スコア:0)
MS-DOSすっかり忘れた
cat *.TXT >> HOGE.TXT
でよさげ
Re:しらんかった (スコア:2)
MS-DOSでテキストを表示するのはcatではなく TYPE コマンドですよ。
さらに、COMMAND.COM のTYPEコマンドはワイルドカードに対応してないので、 TYPE *.TXT はできません
Re:しらんかった (スコア:1)
PowershellでHOGE.TXTがある状態で
を実行すると、無限ループになってHOGE.TXTが際限なく大きくなる。
期待通りの動作であって、これをバグとは言わないと思う。
ちなみに、
だと、ワイルドカード展開の順番でHOGE.TXTが来た時にエラーになる。
HOGE.TXTの内容は、HOGE.TXTが最初に展開されれば変更されないし、そうでなければ、その直前に展開されたファイルの中身と同じになる。
これも期待通りの動作。
MS-DOSだと何か違う動作になったのかな?
Re: (スコア:0)
それはそもそもどんな動作を期待して実行するコマンドなんだ……
コピー先見て勝手にコピー順を変えたり一時ファイル生成されるのも迷惑だし、
逐次実行してってエラー出たら止まりってのは至極普通の動作だろ。
君はエラー時にロールバック(操作前の状態を維持)してほしいかもしれんけど
出来たところまででも結果がほしい、エラー時の状態を知りたいってパターンもある。
シェルに概ねお任せするGUIならともかく、
コマンドなら愚直に実行してくれたほうが有り難いと思う。
気配りしたいなら自分でそういうコマンド列ないしはバッチ書いて好きに制御すべし。
# その意味ではファイル名等のエスケープ関連こそ批難すべき挙動だと思う。
Re: (スコア:0)
当時のやつは、CONFIG.SYSのBUFFERSの設定によると思います。
BUFFERSにそれなりの大きな値を設定してたらフロッピー上のバッチファイルも一度に読み込みますが、BUFFERS=1とかだとカッチンカッチンと…。
Re: (スコア:0)
SUBMIT hoge.SUB
なんてものもありましたな
(*´ω`*)
Re: (スコア:0)
上書きじゃなくてmvしよう。
Re:しらんかった (スコア:1)
はい、仰せの通りに mv しています
Re:しらんかった (スコア:1)
Re:しらんかった (スコア:1)
スクリプト書き換えるときは同じdirectoryでやるからファイルシステムマタギは安全そう。
Re: (スコア:0)
自明かと思って注意しなかった。
renameシステムコールを使おう、ならあってる?
あとはemacs使えとか。
vimはどうかな?
Re:しらんかった (スコア:1)
こうレベルの話だと、「emacsやvimで本番環境のファイルを直接編集する」時点でアウトじゃないですかね。
「あらかじめテスト環境で動作確認を取ってから、本番環境に上げる」ようにしないと。
となると、ファイル更新に使うツールはscpとかrsyncとかだけど、
自分がやるなら、「別ディレクトリにアップしておいてから、rename(mv)」かな。
実行中書き換えの問題がなくても、
「ファイルコピー中の、中途半端な状態のファイルで実行してしまう」リスクが怖いので、
ファイルを用意してからatomicに切り替えるようにすべき。
Re: (スコア:0)
アトミックな置換は大賛成。
だけど、実行中だとアトミックに置換しても逐次読みや別ファイル参照で整合性が失われるから、
実行中の変更を安全に行うのは基本的には不可能だと思ったほうがいいのよな。
Windowsのアップデートが再起動祭りな事に対して
Linuxはアップデートでの再起動をあまり要求しないって誇る人たちが昔は目に付いたけど、
逐次読み、別ファイル参照を考慮するとどっちもどっちっていうね。
Re: (スコア:0)
remove(unlink)じゃね?
openして上書きするのが問題なんであって、消してコピーか、renameで内部的にunlinkすれば安全と。
unlinkさえしてあれば再オープン出来ないから安全になる。
さらにrenameならunlink含めてアトミックだからさらに安心ってことで。
Re: (スコア:0)
処理系やバージョンによるので確かめてからやりましょうが正解では。
Re: (スコア:0)
これを故意に使ったのが自己書き換えプログラムなのでは。
自分では使ったことないけど。
Re: (スコア:0)
広義にはそう言えるかもしれないけど、こういうのはタレコミのソースにもあるように「自己追記」とでも呼ぶべきものであって「自己書き換え」とは言わないすね
Re: (スコア:0)
てっきり最初にスクリプト全部読み込んでから走らせてると思ってた。
そのあたりは処理系の作り方に依存するわけで、うちが今使ってるインタープリタの処理が遅いシミュレーションツールは実行中にソースを消去しても何の問題もなくプログラムの実行が続く
処理系の中身がどうなってるか知らなくも気軽にプログラミング出来るのは良い時代だが、利用者が中の仕組みをまったく意識しないというのも困る
Re: (スコア:0)
逐次読み込みするにしてもシェル側でファイルハンドル握って排他制御くらいしろよと思った。
Re: (スコア:0)
Re:しらんかった (スコア:1)
UNIX系のファイルシステムなら、ロックしててもmvでファイル入れ替え可能です。
inodeでファイルの実体を管理しているので、
名前を変えたり削除しても、ファイル名からの参照ができなくなるだけで実体は残っており、
すでにオープンしているファイルハンドルからはそのまま元ファイルにアクセスし続けられます。
ファイルハンドルを保持せず、都度オープンするような実装だと新ファイルにアクセスすることになりますが、
その場合は「mvコマンドで安全にファイルを入れ替えて」もアウト。
バッチファイルはそういう挙動だったかと思います。