この質問については、bashシェルスクリプトを考えてみましょう。ただし、この質問はすべての種類のシェルスクリプトに適用する必要があります。
誰かがシェルスクリプトを実行すると、Linuxはすべてのスクリプトを一度に(メモリに)ロードしますか、それともスクリプトコマンドを1つずつ読みますか?(一行ずつ)?
つまり、シェルスクリプトを実行して実行が完了する前に削除すると、実行は終了しますか、それとも続行されますか?
答え1
を使用すると、strace
シェルスクリプトの実行時にどのように実行されるかを確認できます。
はい
このシェルスクリプトがあるとしましょう。
$ cat hello_ul.bash
#!/bin/bash
echo "Hello Unix & Linux!"
次のコマンドを使用して実行しますstrace
。
$ strace -s 2000 -o strace.log ./hello_ul.bash
Hello Unix & Linux!
$
strace.log
ファイルの内部を見ると、次のことがわかります。
...
open("./hello_ul.bash", O_RDONLY) = 3
ioctl(3, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0x7fff0b6e3330) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(3, 0, SEEK_CUR) = 0
read(3, "#!/bin/bash\n\necho \"Hello Unix & Linux!\"\n", 80) = 40
lseek(3, 0, SEEK_SET) = 0
getrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=4*1024}) = 0
fcntl(255, F_GETFD) = -1 EBADF (Bad file descriptor)
dup2(3, 255) = 255
close(3)
...
ファイルを読み込むと、次のように実行されます。
...
read(255, "#!/bin/bash\n\necho \"Hello Unix & Linux!\"\n", 40) = 40
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 3), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc0b38ba000
write(1, "Hello Unix & Linux!\n", 20) = 20
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(255, "", 40) = 0
exit_group(0) = ?
上記では、スクリプト全体が単一のエンティティとして読み込まれ、そこで実行されているように見えることが明らかになります。だからそうだろう「ナタナダ」少なくともBashの場合は、ファイルを読み込んで実行します。それでは、実行中にスクリプトを編集することは可能だと思いますか?
メモ:しかし、そうしないでください!スクリプトファイルの実行を妨げてはいけない理由については、読んでください。
他の通訳者はどうですか?
しかし、あなたの質問に問題があります。 Linuxは必ずしもファイルの内容をロードするわけではなく、コンテンツをロードするのはインタプリタなので、ファイルを完全にロードするのか、一度にチャンクまたは行ずつロードするのかは、インタプリタの実装方法によって異なります。
では、なぜファイルを編集できないのですか?
しかし、より大きなスクリプトを使用すると、上記のテストが少し誤解を招く可能性があることがわかります。実際、ほとんどのインタプリタはファイルをチャンクとしてロードします。これは、ファイルチャンクをロードして処理し、他のチャンクをロードする多くのUnixツールの標準です。しばらく前に、私が書いたU&L Q&Aでこの動作を見ることができますgrep
。grep / egrepは毎回どのくらいのテキストを消費しますか?。
はい
次のようなシェルスクリプトを書いているとしましょう。
$ (
echo '#!/bin/bash';
for i in {1..100000}; do printf "%s\n" "echo \"$i\""; done
) > ascript.bash;
$ chmod +x ascript.bash
このファイルを生成します。
$ ll ascript.bash
-rwxrwxr-x. 1 saml saml 1288907 Mar 23 18:59 ascript.bash
これには次の種類のコンテンツが含まれます。
$ head -3 ascript.bash ; echo "..."; tail -3 ascript.bash
#!/bin/bash
echo "1"
echo "2"
...
echo "99998"
echo "99999"
echo "100000"
ここで上記と同じ手法を使って実行すると、次のようになりますstrace
。
$ strace -s 2000 -o strace_ascript.log ./ascript.bash
...
read(255, "#!/bin/bash\necho \"1\"\necho \"2\"\necho \"3\"\necho \"4\"\necho \"5\"\necho \"6\"\necho \"7\"\necho \"8\"\necho \"9\"\necho \"10\"\necho
...
...
\"181\"\necho \"182\"\necho \"183\"\necho \"184\"\necho \"185\"\necho \"186\"\necho \"187\"\necho \"188\"\necho \"189\"\necho \"190\"\necho \""..., 8192) = 8192
ファイルは8KB単位で読み取られるため、Bashや他のシェルはファイルを完全にロードせずに代わりにチャンクで読み取ることができます。
引用する
答え2
これはオペレーティングシステムよりもシェルに依存します。
バージョンに応じて、要求に応じてksh
スクリプトを8,000バイトまたは64,000バイト単位で読み取ります。
bash
スクリプトを1行ずつ読んでください。ただし、行の長さに制限がないことを考慮して解析するたびに、次の行の先頭から8176バイトを読みます。
これは単純な構造、つまり単純な命令セットのためのものです。
シェル構造コマンドを使用する場合(許容される回答はケースを考慮しません。)for/do/done
ループ、case/esac
スイッチ、hereドキュメント、括弧で囲まれたサブシェル、関数定義などと上記の組み合わせと同様に、シェルインタプリタは最初に構文の終わりまで読み込み、構文エラーがないことを確認します。
これは同じコードを複数回読み取ることができるため、やや非効率的ですが、これらのコンテンツは通常キャッシュされているため軽減できます。
どのシェルインタプリタを使用しても、シェルスクリプトの実行中にシェルスクリプトを変更することは非常に賢明ではありません。シェルはスクリプトのすべての部分を自由に読み直すことができるため、同期されていないと予期しない構文エラーが発生する可能性があります。
また、bashがksh93が完全に読み取れないほど大きなスクリプト構成を保存できない場合、分割違反によってクラッシュが発生する可能性があります。
答え3
スクリプトを実行するインタプリタの動作方法によって異なります。カーネルが行うことは、実行されるファイルがで始まり、#!
本質的に残りの行をプログラムとして実行して、実行可能ファイルを引数として提供することに気づくことです。ここにリストされているインタプリタがファイルを1行ずつ読み込むと(対話式シェルが入力した内容を処理するかのように)、次のような結果が得られます(ただし、複数行のループ構造は繰り返しのために読み取られて保持されます)。これを処理して(おそらくPerlやPytonのように中間表現でコンパイル)、実行する前にファイル全体を読みます。
同時にファイルを削除すると、インタプリタがファイルを閉じるまで削除されません(通常、最後の参照(ディレクトリエントリまたは開いていたプロセス)が消えるとファイルも消えます)。
答え4
「x」ファイル:
cat<<'dog' >xyzzy
LANG=C
T=`tty`
( sleep 2 ; ls -l xyzzy >$T ) &
( sleep 4 ; rm -v xyzzy >$T ) &
( sleep 4 ; ls -l xyzzy >$T ) &
echo alive. ; sleep 1
echo alive. ; sleep 1
echo alive. ; sleep 1
echo alive. ; sleep 1
echo alive. ; sleep 1
echo alive. ; sleep 1
echo alive. ; sleep 1
echo alive. ; sleep 1
dog
sh xyzzy
走る:
~/wrk/tmp$ sh x
alive.
alive.
alive.
-rw-r--r-- 1 yeti yeti 287 Mar 23 16:57 xyzzy
alive.
removed `xyzzy'
ls: cannot access xyzzy: No such file or directory
alive.
alive.
alive.
alive.
~/wrk/tmp$ _
IIRCプロセスがファイルを開いたままにしている限り、ファイルは削除されません。削除は単に与えられた DIRENT を削除します。