はじめに
面接官「ほう。得意な言語はPerlですか」
学生「はい!」
面接官「では、10000までの素数を出力してください」
学生「system "seq 2 10000 | factor | awk 'NF == 2' | cut -d: -f1"」
面接官「げぇっ シェル芸人」— ぐれさん (@grethlen) February 27, 2014
面接官「ほう。得意な言語はPerlですか」 学生「はい!」 面接官「では、10000までの素数を出力してください」 学生「system “seq 2 10000 | factor | awk ‘NF == 2’ | cut -d: -f1″」 面接官「げぇっ シェル芸人」
まあ!素敵!
あら?Perl でと出題されていますのに、シェルで解答なさっていらっしゃるようですわね。それで、面接官が「げぇっ」となってしまいましたのね!面白いですわ♪
さて、今回はこのシェル部分に注目し、各コマンドについて調べることでシェルに対する理解を深める、勉強をしたいと存じます♪
10000 までの素数を出力するシェル
seq 2 10000 | factor | awk 'NF==2{print $2}'
- seq – 単調増加 (減少) する数値列を表示する
Man page of seq - factor – 素因数分解をする
Linuxコマンド集 – 【 factor 】 素因数分解をする:ITpro - awk – テキストの置換処理に長けたスクリプト言語
Man page of GAWK ※ awk のマニュアルではないが、参考になる。 - cut – テキスト・ファイルの各行から一部分を取り出す
Linuxコマンド集 – 【 cut 】 テキスト・ファイルの各行から一部分を取り出す:ITpro ※ 上記コマンドには無いが、ツイッターでは使用していたので記述
最初に引用したツイートのシェル部分から最後の部分のみ変更しています。いろいろ調べていましたら、「cut」コマンドは「awk」コマンドを工夫することで省略できましたから。
さて、具体的に出力を確認しながら各コマンドを勉強してまいりましょう。その際、10000 までですと出力が多すぎますので、10 までの数で考えます。
「seq 2 10」で 2 〜 10 の数字を表示
他にもオプションがございますけれども、
- seq FIRST LAST
FIRST から LAST まで、1 ずつ加えた数値を表示する。
です。次のように表示されますわ。
なお、今後の説明をしやすくするために、表を用いておりますけれども、CUI の画面では、ただ単に数字が 1 行に 1 つ表示されているだけですの。
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
10 までの数の中で素数は 2、3、5、7 ですわね。これらをどうやって炙り出せばよいのかしら?
素数の定義に立ち返りましょう。素数とは!
素数(そすう、英: prime number)とは、1 と自分自身以外に正の約数を持たない自然数で、1 でない数のことである。
大雑把な表現ですけれども「自分自身以外に約数がない」が最大のヒントですわ!つまり、素因数分解してみれば次の取っ掛かりになりますの♪
「seq 2 10 | factor」で 2 〜 10 の各数字を素因数分解して表示
先ほど出力した 2 〜 10 を引数に、それぞれの数字を factor で素因数分解して表示します。
- factor [ number ] …
number 素因数分解する数を指定する
指定した数を素因数分解する。結果は1行で表示され、複数の素因数がある場合は、スペースで区切って表示する。
この結果、次のように表示されますの。
2: | 2 | ||
3: | 3 | ||
4: | 2 | 2 | |
5: | 5 | ||
6: | 2 | 3 | |
7: | 7 | ||
8: | 2 | 2 | 2 |
9: | 3 | 3 | |
10: | 2 | 5 |
まあ!素数が見えてきましたわ!3 列目、4 列目が存在する数、つまり「自分自身以外に約数がある」数がひと目で分かります。これらの行を削除できれば、素数のみの行にしぼることができますわね!
「seq 2 10 | factor | awk ‘NF==2{print $2}’」で 「x: y z …」形式の行の中から「x: y」の行のみ抽出、そして「y」の部分のみを表示
一気に表現しようと思うと、大分難しくなってまいりました。整理いたしましょう。
awk についてあれこれ基本を勉強します!
awk コマンドの中身を見て行く前に基本的な事を勉強いたしましょう。次のページが参考になりました。何度も読み返しました。大変わかり易く、awk に対して愛情を感じる筆致で、素敵な意味で変態的、尊敬できるページでございます。ありがとう存じます♪
「awk」の次に書くことの全体を「”」シングルクォーテーションで囲み、更にその中でアクションを「{}」中括弧で囲みます。
- awk ‘パターン{アクション}’
- 条件 = パターン
パターンに一致するものに対して、次のアクションをとる、というように考える。 - 何らかの処理 = アクション
パターンに一致したものがやってくるので、アクションに書いたことを行う。大体は print で、画面に表示する事が多い。
次に、awk で扱うデータについて確認です。
- 行 – レコード(Record)
- 列 – フィールド(Field)
今回の例で言いますと、「2: 2」、「3: 3」や「4: 2 2」が行、レコードです。そしてスペースが区切り文字ですので「2:」、「2」や「3:」が列、フィールドです。
素数行を抽出し、綺麗に表示する awk の中身を追う♪
まず、「seq 2 10 | factor」は今まで説明しました。「x: y z …」といった行が表示されたのでした。これを引数に「awk ‘NF==2{print $2}’」という処理を行います。
まず、awk の「NF==2」とは何かしら?「フィールドの数が ” 2 ” のレコード」ですわね。
- NF – 現在の入力レコードのフィールド数。
そのパターンに一致するレコードに対してのみ、アクション「print $2」を実行します。これは難しくありませんわね。「2 番目のフィールドのみを出力」ですの。
- print $n – n 列目のデータを出力
- print は awk の関数で、画面にデータを出力
- $n は awk が用意した変数で、n 番目のフィールドを指す。$1 → 1 列目のデータ、$2 → 2 列目のデータ、$3 → 3 列目のデータ。$0 は全てのフィールド、つまり 1 レコード全体のデータが入っている。
はい、これで準備が整いました。具体的に見て行きましょうね。
1.awk ‘NF==2{print $2}’ の パターン NF==2 でフィールド数が 2 の行のみが選択されます。
2: | 2 | ||
3: | 3 | ||
4: | 2 | 2 | |
5: | 5 | ||
6: | 2 | 3 | |
7: | 7 | ||
8: | 2 | 2 | 2 |
9: | 3 | 3 | |
10: | 2 | 5 |
↓
2: | 2 | ||
3: | 3 | ||
5: | 5 | ||
7: | 7 |
2.awk ‘NF==2{print $2}’ のアクション print $2 で 2 番目のフィールドを出力します。
2: | 2 | ||
3: | 3 | ||
5: | 5 | ||
7: | 7 |
↓
2 |
3 |
5 |
7 |
これで素数が画面に出力されました!おしまい!ヤッタネ!
おわりに
冒頭のツイッターをそのまま勉強するだけになるかしら?と予想しておりました。けれども、awk の組み込み変数を知ることで、最初のコマンドから応用へと至ることができました。
とっても嬉しいですの♪
awk は奥が深いですわね。以前に取り上げたこともございました。このときはウェブのアクセスログなどの解析に使用したのでした♪
さて、そもそもきっかけとなったツイッター、面接官が学生にプログラムを書いてご覧、きっと書けないから!という雰囲気を感じます。
就職活動時の面接で、自分を大きく見せようと、実力が足りないのにあれができます、これができます、と言っていると、じゃあ、今やってみてね♪と反撃を食らう、そのような場面を表している流れのひとつに現れたツイートと存じます。
ですがこのツイートでは見事に面接官をあしらっておりますね♪しかも、本来の指示した Perl はほんの少し、メインはシェルで実現する、その斜め上の方法が面白さをさらに盛り上げます♪
翻ってわたくしたちを考えますと、はい、おそらく紙とペンだけでは Hello World! すら難しいと存じます><。どのような言語でも><!
インターネットや書籍、サンプルをひな形に、いつも書いておりますもの><!IDE のお世話になって、いつも補完してもらいますもの><!
素人でしたらそれで充分ですけれども、誇りある職業プログラマーでしたら胸を張れませんわね。。。
そのようなことも感じましたわ♪
以上です。