こんにちは、シェルスクリプト大喜利司会のもっと吹く編集長でございます。さぁ明日から週末三連休、皆さんどんな予定を立てていらっしゃいますか?アタクシは、金沢行ってきまーす。……ただし仕事で(泣)
というわけでこれからやってくる楽しい楽しい三連休。シェルスクリプト大喜利のお題に挑み、ちょっとアヤしい喜びを感じてみるってのはどうですか? この投稿のサブタイトルにもありますように、"for,while禁止"という苦痛を伴うお題が今回あるんですが、ナゼかこれに対する投稿が殺到しとります。
ということで、今回またまたシェルスクリプト大喜利のご案内です。このコーナーは冊子版とは別に毎回無料で読めますので是非一度ご覧ください。さて次回の大喜利は第八回。第七回の名(迷)解答も公開されておりますので是非ご覧ください。そして……、挑んでください! 3つのお題に。
Linux JMに載っているコマンド(および仕様)と、USP研究所がリリースした拡張コマンドセットOpen usp Tukubaiだけで解答に挑んでもらい、厳密な正解よりも解答の面白さ、美しさ、はたまたしょーもなさを重視するというこのコーナー。本で読んだ方、より抜き版(無料版)で読んだ方、このブログ記事を読んだ方、誰でも参加できますので投稿お待ちしております。
1~n(nは引数で指定)の自然数の中の累乗数を全て求めるシェルスクリプトを書いてください。
前回に引き続き、またまた整数数列ネタです。なぜか整数数列問題が人気なんですよね~。今回も既に投稿をいただいていますがやはり人気。(ただ今回はそれ以上に第三問が人気なのですが)
累乗数とは何かと言うと、a = bc (a,b,cは全て自然数)と書き表せる数aのことです。
例えば、最も小さい数は1です。1 = 11と書けますね(1は特殊で1 = 12でも1 = 13でも……無数にあるという)。それから9や27なんてのもそうですね。それぞれ、32、33です。あと64のように、26でもあり43でもある累乗数もあります。こういった数を見つけるアルゴリズムを披露してくださいというわけです。もちろん、シェルスクリプト(Linux JMとTukubaiの範囲)で。
考えられる数の組み合わせを1つ1つ順番に試していくプログラムさえ組めば解けるお題なので、プログラムを書けるなら全く解法が思いつかないということはないと思います。しかし、それをいかにスマートに、あるいはしょーもなくするかが腕の見せ所! これまで寄せられている投稿を見ると、1を特別扱いしているものが多いのですね。もちろん特別扱いしようが答えをちゃんと出してくれさえすれば正解なのですよ。でもやっぱり1を特別扱いしないプログラムになっているとポイント高いですね。
この大喜利お題が掲載されている号のUSP MAGAZINEの別記事に、英単語の文字ソートをやっているプログラム(動作は後述)がありました。しかしPerlで組まれてました。
確かにPerlで組むとほんの数行で書けてしまってラクなのですが、大喜利司会者のアタクシとしては、やっぱりシェルスクリプト版が欲しい! なので、シェルスクリプト版を作ってください。
別記事というのは、「やわらかマッドサイエンティスツのプログラミング入門 #4」という記事です。冊子版にのみ掲載されている記事なのですが、どういう内容だったかといいますと、データフローダイアグラム(DFD)や関数型プログラミングについて紹介した後、実はシェルスクリプトには関数型プログラミング的な一面がある!ということで、いろいろとシェルスクリプトの演習問題を解くという記事だったのです。あ、元々はUSP友の会の勉強会ネタだったんです。ちなみに次回のベリーエキサイティンな勉強会が絶賛申込中なのでいらしてください。
前置きが長くなりましたがまずPerl版のプログラム(add_sorted_word.pl)を掲載します。
#! /usr/bin/env perl while (<>) { chomp; print sort(split(//)), " $_\n"; }
「てやんでぃ、こちとらぁ生粋のシェルっ子でぃ! Perlのコードなんか読めやがるかってんだ!」と叱られちゃいそうなので動作例を紹介します。
まずはこんな英単語の元データ(dic.txt)があったとします。
pans pots opt snap stop tops
一行に一つの英単語が記された単純なテキストファイルです。お題を簡単にするため小文字だけ並んでいるものとします。これを先程のPerlプログラムに掛けるとこうなります。
> cat dic.txt | ./add_sorted_word.pl anps pans opst opts opt opt anps snap opst stop opst tops >
つまり英文字ソートをした結果文字列を、元の文字列の手前に挿入し、一行二単語にする。ただしデータは標準入力から受け取る、という動作です。
さて、シェルスクリプトで行内ソートはどうやって実現すればいいのでしょうか??? それがこのお題の最大の肝ですね。
for文やwhile文を一切使わずに、九九の表を書いてください。
01*01=01 01*02=02 01*03=03 … 01*09=09
02*01=02 02*02=04 02*03=06 … 02*09=18
:
:
09*01=09 09*02=18 09*03=27 … 09*09=81
といった感じです。
さあ、シェルスクリプト大喜利第八回のお楽しみのお題がやってきましたよ。通常ならforやwhile等のループ文を使ってちょちょいのちょいとコーディングするであろう課題を、それらを使わないでやりなさいという、なんてサディスティックなお題なことか。ところが!!!現在のところ、今回の三つのお題の中で一番投稿数の多いお題になってるんですよ。まさかここまでマゾヒストが多いとは……。いゃいゃ、そんなアタクシも結構マゾヒストです。
さて、forもwhileも無しで一体どうやるんでしょうねぇ。え、「if文があるじゃないか」って? でもgoto文がありませんよ。あ、Cシェルにはgoto文ありますね。というわけでif文使って投稿するってのもレアでいいかもしれませんよ。:-)
あとは、今回の大喜利の投稿が参考になりますね。今回寄せられた投稿の中に、ループ文を避け、なんとBashのブレース展開を利用しているものがあったんです。いゃあ「そう来たか……」という思いでした。
そして既に投稿してくださっている皆さんの答えもまた、実にバラエティー豊かです。そもそも、シェルスクリプトって、コマンドを駆使すれば殆どのループ文を取り除けちゃう言語なのですよ。そこが、遅い遅いと言われがちなシェルスクリプトを高速化するための秘訣であり、関数型プログラミングっぽい一面を持つと言われる所以なんですけどね。
笑いをとるのは苦手だけど、魅せるコードを書くのなら自信あり!そんな貴方の投稿を大募集。
大事な大事な今回の締め切りは、
です。尚、この締め切り内であれば、何度投稿しても構いません。つまり、修正投稿もOKですよ。
出題したお題が「なんだそんな程度か!」と物足りなさを感じるかもしれないです。そうお思いのそこのシェル通の貴方! 是非ともお題を出してみませんか!
もしくは「お題ではないけれども、自分で作った自慢のコードがある」という人は、自慢したいポイントの解説を添え、それを送ってくれるのも大歓迎。そしたらこちらでお題化しちゃいまずぞ。
そしてお題として採用させていただいた方にも段位を進呈。
宛先は解答と同じく mag(あっと)usp-lab.com (アットマークに読み替えてください)へ!
制限の多いプログラミングを強いられるとコーフンするというアナタの投稿、お待ちしてます。いゃ、そうでなくてももちろん大歓迎です。