【自習】第66回シェル芸勉強会【シェルのプロセスIDで遊ぼう】

現在、介護老人保険施設に入所している母との面会が毎週土曜日の午後にあるため、今回も配信録画で自習しました。

今回はデータファイルを操作する出題はみられず、Bashの特殊変数$$でシェルのプロセスIDが得られることを利用した問題や、数字を使わずに解答する問題などトリッキーな出題が多くみられました。



Q1

0123456789と出力してください。コマンド内で数字を使わないでください。

A1

$ printf '\n\n\n\n\n\n\n\n\n\n' | cat -n | sed 's/ *//;$s/.//' | sort | xargs | sed 's/ //g'
0123456789

Q2

つぎのコマンドについて、?の部分になにか書いて、filelsの吐くエラーを記録してください。?に入れる文字列は何文字でもいいですが、半角スペースと数字は禁止します。

$ ls 存在しないファイル 3>file 2>?
$ cat file
ls: '存在しないファイル' にアクセスできません: そのようなファイルやディレクトリはありません

A2

$ ls 存在しないファイル 3>file 2>&$(($$/$$+$$/$$+$$/$$))
$ cat file
ls: '存在しないファイル' にアクセスできません: そのようなファイルやディレクトリはありません

Q3

1, 2, 3, 4文字それぞれで終了ステータス1を出す方法を考えてみてください。ファイルを操作するためのコマンドの使用(mvrsynccpなど)や、なくても終了ステータス1が出るような文字を加えて文字数を水増しする方法は禁止です。また1〜4文字まで、互いになるべく違う方法を考えてみてください。

A3

# 1文字で終了ステータス1を出す:
# `!`は終了ステータスを論理否定する`bash`の予約語
$ !
$ echo $?
1

# 2文字で終了ステータス1を出す:
# 入力のリダイレクトによるカレントディレクトリに存在しないファイル`f`の読み込み
$ <f
bash: f: そのようなファイルやディレクトリはありません
$ echo $?
1

# 3文字で終了ステータス1を出す:
# `hcd`はClassic Mac OSで用いられていたHFSファイルシステム用の`cd`コマンド
$ hcd
hcd: No volume is current; use `hmount' or `hvol'
$ echo $?
1

# 4文字で終了ステータス1を出す:
# 後述のA4で用いているのと同じ方法(`w`はログイン中のユーザーとその人のプロセスに関する情報を表示するコマンド)
$ w>&-
w: write error: 不正なファイル記述子です
$ echo $?
1

Q4

シェルに細工をしてtrueを実行したあとのecho $?の出力を非ゼロにしてください。trueはビルトインコマンドでも外部コマンドでもかまいません。

A4

$ /bin/true --version >&-
/bin/true: 書き込みエラー: 不正なファイル記述子です
$ echo $?
1

外部コマンドのtrueにはバージョン情報を表示する--versionオプションがあることと、bashのリダイレクトでは>&-という形式で任意のファイル記述子を閉じられることを利用しています。


Q5

どこかのプロセスにおいて、現状のシステムの設定で作れる最も大きい番号のファイル記述子を作って、/proc/プロセス番号/fdを使って存在を確認してください。確認までワンライナーでお願いします。できる人はワンライナー中で数字を使わないでください。

A5

# `/tmp`ディレクトリに移動してから実行
$ perl -E 'mkdir "D";for('a'..'zzz'){open $_,">","D/$_" or exit;$n=fileno $_}END{system("ls -l /proc/$$/fd/$n");system("rm -fR D")}'
l-wx------ 1 mitsuhisa mitsuhisa 64 10月  6 01:42 /proc/7382/fd/1023 -> /tmp/D/amg

現状のシステムの設定で作れるファイル記述子の個数はulimit -nで知ることができ、解答例の/proc/7382/fd/1023と対応していることがわかります。

# 有効なファイル記述子の値は0から1023までの1024個
$ ulimit -n
1024

Q6

いまのBashのプロセスで、10以上のファイル記述子を使い切ってください。できる人はワンライナー中で数字を使わないでください。

A6

# ワンライナー実行前:
$ ls /proc/$$/fd | sort -n
0
1
2
255

# 解答例のワンライナーを実行:
# `n`の値が255(既存の数値)と1024(ファイル記述子の最大値+1)の場合はエラー
$ Z=$(($$/$$+$$/$$)); for n in $(seq $(((Z<<Z)+Z)) $(ulimit -n)); do exec {n}>&$Z; done
bash: リダイレクトエラー: ファイル記述子を複製できません: ファイルを開きすぎです
bash: 2: ファイルを開きすぎです
bash: リダイレクトエラー: ファイル記述子を複製できません: ファイルを開きすぎです
bash: 2: ファイルを開きすぎです

# ワンライナー実行後:
$ ls /proc/$$/fd | sort -n
0
1
2
10
11
12
13
14
15
16
(...略...)
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
Written on October 30, 2023