shellgei/shellgei160

問題22別解について

motimotinoyamayama opened this issue · 2 comments

問題22の別解1,2が解答見ても理解できませんでした。
コマンド一つ一つの意味が難しいです。

教えていただけないでしょうか。よろしくお願いします。

@motimotinoyamayama こちら、反応が遅くなり恐縮です。
Close になりましたが、疑問点についてはクリアになりましたでしょうか。

いずれも少々トリッキーな別解であり、特にjoin の説明などは本書の後半になっておりますので、一旦読み飛ばして後で改めて理解にチャレンジいただくのも良いかなと思います。

念の為、別解の理解のための簡単な参考情報を追加しておきます。
もし疑問点がより文章化できればリオープンして再度ご質問ください。

別解1 の読み取りのヒント

一般的に末尾が | bash| sh で終了するコマンドは、
その箇所をとって動作確認すると少しやっていることがわかることがあります。
別解1 は以下のようになります。

$ seq -f 'echo $(grep -E "^[a-z]+$" /usr/share/dict/words|shuf -n1).$(shuf -n1 -e {com,org,{co.,}jp,net}) # %g' 100
echo $(grep -E "^[a-z]+$" /usr/share/dict/words|shuf -n1).$(shuf -n1 -e {com,org,{co.,}jp,net}) # 1
echo $(grep -E "^[a-z]+$" /usr/share/dict/words|shuf -n1).$(shuf -n1 -e {com,org,{co.,}jp,net}) # 2
echo $(grep -E "^[a-z]+$" /usr/share/dict/words|shuf -n1).$(shuf -n1 -e {com,org,{co.,}jp,net}) # 3
︙

別解1は、上記を bash に与え、シェルスクリプトとして実行している、ということになります。
なお、上記の # 1# 2 という記述はシェルスクリプトのコメントになり、コマンドの実行においては意味をなしません。
$(...){com,org,{co.,}jp,net} の記載については、書籍のコマンド置換や、ブレース展開の説明をご参照ください。

なお、前提として、seq コマンドは -f オプションと、%g を含んだ文字列を指定すると、%g を番号に置き換えてその文字列を出力してくれる機能があります。

$ seq 3
1
2
3
$ seq -f '[[[ %g ]]]' 3
[[[ 1 ]]]
[[[ 2 ]]]
[[[ 3 ]]]

そして、別解1は、この機能を使ってシェルスクリプトを作成し、bash に入力して実行するアプローチをとっています。
以下は別解1と同じようなアプローチをとってシェルスクリプトを生成して実行している例です。
echo test というコマンドを 3 回実行するシェルスクリプトを生成し、bash に実行させています。

$ seq -f 'echo test # %g' 3
echo test # 1
echo test # 2
echo test # 3
$ seq -f 'echo test # %g' 3 | bash
test
test
test

seq-f は番号(%g)を指定しないといけないため、コメントという扱いにして結果に含めています。

別解2 の読み取りのヒント

多くの解答・別解で、プロセス置換 <(〜) の箇所は「その内部のコマンドを実行結果を格納したファイル」と置き換えができます。
別解2 では <(cat /usr/share/dict/words | sed '/[^a-z]/d')<(printf '%s\n' com org info co jp ac jp) の 2種類がありますので、それをファイルに格納してみましょう。

$ cat /usr/share/dict/words | sed '/[^a-z]/d' > file1
$ printf '%s\n' com org info co jp ac jp > file2

それぞれを対応する箇所のファイルと置換すると、別解2 は下記のように少しシンプルになります。
これを実行しても答えが得られます。

$ printf '%s\n' www mail ns mx log radius ap | join -j9 -t. - file1 | join -j9 -t. - file2 | sed s/..//
︙
(出力が長いので Ctrl + C で中断)

ここから、前段のパイプから順番にコマンドを一つ一つ実行していただいて、どのあたりが理解が及ばない動作かどうかご共有いただけると、更に何か参考情報がお伝えできるかもしれません。

$ printf '%s\n' www mail ns mx log radius ap
$ printf '%s\n' www mail ns mx log radius ap | join -j9 -t. - file1
$ printf '%s\n' www mail ns mx log radius ap | join -j9 -t. - file1 | join -j9 -t. - file2

なお、本書にもありますが join の説明については練習6.1.c もご参照ください。