- ベストアンサー
実行中のシェルスクリプト自体を修正した場合の動作
シェルスクリプトで自分自身を削除するような構文を組んだとしても最後まで実行されました。 しかし、自分自身に別の同名ファイルを上書きコピーした場合は、 中途半端にコピー後のシェルが実行されました。 お聞きしたいのは、 ・「削除した場合でもスクリプトは最後まで実行される」という認識は正しいのか ・コピーした場合はどうなるのか の2点です。 今回試したところ、コピーした場合は2行目の途中からコピー後のスクリプトが実行されたのですが、 これはマシンのスペックによるのでしょうか? 「コピーした場合はどうなるのかわからない」と判断した方がよいでしょうか? 現在、自分自身を修正するようなスクリプトを作成したいのですが、 上記認識で作ってよいのかどうか迷っています。 よろしくお願いします。 ▼以下、今回試した内容です。 goというスクリプトを作成しました。 #!/bin/bash rm -rf ./go echo "1" echo "2" echo "3" echo "4" echo "5" のように書かれています。 これをカレントディレクトリで ./go のように実行します。 実行結果は特にエラーメッセージも出ず、 goスクリプトは消え、1~5がコンソールに表示されました。 ファイル自体を削除されてもスクリプトを終えるまではコマンドは生きているように見えます。 上記goファイルのrm -rf ./goを、 cp -rf ../go . に修正し、 上の階層に同名のgoスクリプトを用意します。 こちらのgoには #!/bin/bash cp -rf ../go . echo "A1" echo "A2" echo "A3" echo "A4" echo "A5" と書いています。 この状態で、最初の階層でgoを実行します。 最初の実験結果から、 ・カレントのgoの内容は上の階層のgoをコピーされたもの(echo "A1"~の方)になる。 ・コンソールには1~5が表示される と考えました。 実際は、当然goファイルは上の階層のgoをコピーしたものになりましたが、 コンソールには、 ./go: A1: command not found A2 A3 A4 A5 と表示されました。 2行目の途中から、上の階層のgoの内容が実行されているように見えます。 また2回目の環境でコードを、 #!/bin/bash rm -rf ./go cp -rf ../go . echo "1" echo "2" echo "3" echo "4" echo "5" にした場合は、コンソールに表示されたのはA1~A5ではなく1~5でした。 ▲上記が試した内容です。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
まずunix/linuxのファイルシステムの基本として、rm しただけではファイルは消えません。オープン中のファイルをrmした場合、そのファイルをオープンしているプロセスがすべて終了した段階で削除されます。それまでは元のファイルが読み書きされます。 シェルは、一文ずつファイルから読み込んで実行します。実行中にファイルが上書きされることは想定していないので、cp で上書きした場合は、cp文の末尾のバイト位置の次から読み続けられます。従って、新しいファイルの途中から続行されることになります。そのバイト位置が新しいファイルで文の途中であれば、おそらくエラーになりますね。試された状況では、ファイルの前半が同じなのでちょうどうまく続行できたわけです。 rm して cp した場合は上書きではありませんので、最初に書いたとおり、シェルはrmした古いファイルを読み続けることになります。
その他の回答 (2)
- chie65536
- ベストアンサー率41% (2512/6032)
>bashが何をしているのかについては何を見たらよいのかわからないのですが GNU-BashはGNU精神に基づきソースコードが公開されている(バージョンによってはソースコードを自前でコンパイルしてインストールする)ので、GNUソースコードライブラリを参照し、ソースコードを読んで下さい。 ソースコードを読めば、bashが何をしているか判ります。
お礼
回答ありがとうございます。 ソースコードを見ても理解できそうにありませんが、 探してみます。
- chie65536
- ベストアンサー率41% (2512/6032)
「OSのバージョンと、bashの実装に依存する」が答え。 もしbashが「スクリプトをオープンしたまま」であれば「オープン中のファイルを削除しようとした場合にrmはどういう挙動にでるか?」って事になる。 もしbashが「スクリプトを1行実行する度に、fgetsで1行づつ読み込みしている」であれば「オープン中のファイルに上書きした場合にfgetsはどういう挙動にでるか?」って事になる。 もしbashが「スクリプトを最初に全部読み込んでしまう」であれば「実行開始したら自己の変更は不可能」って事になる。 で、OSが変われば(FreeBSDとかSoralisとかLinuxとか)bashの実装方法も変わるし、rmやcpやfgetsの実装方法も異なる。 つまり「今の、その環境ででは、そう動く。環境が変わったら同じ動きをする保証はどこにもない」と言う事。 環境によっては「core吐いて止まる」かも知れませんよ。
お礼
回答ありがとうございます。 よくわかったような気がします。 bashが何をしているのかについては何を見たらよいのかわからないのですが、 (試してみるしかないわけじゃないと思いますが) このディストリビューションで同じようにインストールしたもの(デフォルト状態)であれば同じ動きをする、 ということはわかったので問題なさそうです。 使おうとしている環境は同じですので。 挙げた例の、 rm -rf ./go cp -rf ../go . を使って修正(更新)してみようと思います。 ありがとうございました。
お礼
回答ありがとうございます。 よくわかりました。 rmでいきなり消えるわけじゃないんですね。 LinuxはWindowsと違って消したらアウトみたいなイメージがありましたけど。 少し前に作ったスクリプトは、テストして巧く動いたので使い始めましたが、 テスト中は「ちょうどうまく続行できた」だけであることがわかりました。 あああ早く修正してこないと…。