第8回シェル芸勉強会問題集を解いてみた - 拡張 POSIX シェルスクリプト Advent Calendar 2013 - ダメ出し Blog

2013-12-22(Sun) [sh][shell] [更新履歴]

拡張 POSIX シェルスクリプト Advent Calendar 2013、22日目の記事です。

なるべく POSIX sh で、無理なものは bash, ksh で解きました。 外部コマンドなし縛り。(md5sum は除く)

問題1 数字の並びを 2つずつフリップする

#!/bin/sh
echo 1 2 3 4 5 6 7 8 9 10 |
(
set -- `read l; echo $l`
r=''
while [ $1 ]; do r="$r $2 $1"; shift 2; done
echo $r
)
# 2 1 4 3 6 5 8 7 10 9

問題2 「ユニケージ」「ユニゲージ」「UPS」「USP」の各個数を数える

#!/bin/bash
echo ユニゲージユニケージユニゲージUSP友の会USP友の会 UPS友の会UPS友の会 |
(
read l
ns=
for k in ユニケージ ユニゲージ UPS USP; do
  n=0
  while :; do
    x="${l/$k/}"
    [[ $x = $l ]] && break
    ((n++))
    l="$x"
  done
  ns="$ns $n"
done
echo $ns
)
# 1 2 2 2

問題3 4個のファイルを作り同じ内容のものを探し出すワンライナー

パス。あとでやる。

問題4 数字の列を偶数と奇数に分ける

sh 版。

#!/bin/sh
echo 3 8 2 10 1 8 9 |
(
read l
e=
o=
for n in $l; do
  case $n in *[13579]) o="$o $n";; *) e="$e $n";; esac
done
echo $e $o
)
# 8 2 10 8 3 1 9

bash 版。

#!/bin/bash
echo 3 8 2 10 1 8 9 |
(
read l
e=
o=
for n in $l; do
  ((n%2)) && o="$o $n" || e="$e $n"
done
echo $e $o
)
# 8 2 10 8 3 1 9

問題5 ビット列の 0 と 1 の連続数を数える

#!/bin/sh
echo 000001111111111001010 |
(
read l
r=
[ "${l#0}" = "$l" ] && m=0 || m=1
while :; do
  p=${l%%$m*}
  [ -z "$p" ] && break
  [ $m -eq 0 ] && m=1 || m=0
  r="$r $m"
  [ ${#p} -gt 1 ] && r="$r${#p}"
  l=${l#$p}
done
echo $r
)
# 05 110 02 1 0 1 0

問題6 連続する数列をハイフンでまとめる

以前やったネタだけど、 出力形式が微妙に異なるので調整した。

#!/bin/bash
echo 1 2 3 5 6 8 10 11 12 15 |
(
read l
s=${l%% *}
((p=x=s-1))
for n in $l x; do
  ((n-p-1)) && { 
    ((p-x)) && o=$o-$p
    o="$o $n"
    x=$n
  }
  p=$n
done
o=$s${o#-$s}
echo ${o% x}
)
# 1-3 5-6 8 10-12 15

問題7 数字3桁のパスワードの MD5 ハッシュ値から平文パスワードを求める

#!/bin/bash
echo 250cf8b51c773f3f8dc8b4be867a9a02 |
(
read l
n=0
while [[ $n -lt 1000 ]]; do
  p=$(printf '%03d' $n)
  h=$(echo -n $p |md5sum)
  if [[ ${h%% *} = $l ]]; then
    echo $p
    break
  fi
  ((n++))
done
)
# 456

問題8 /usr/share/dict/wordでしりとり

ksh で適当に実装。 「é」とか含まれているので bash だと動かない。

#!/bin/ksh

typeset -a words
typeset -l word_lower

for letter in {a..z}; do
  eval typeset -a words_by_"$letter"
done

while read -r word; do
  word_lower="$word"
  words+=("$word")
  letter="${word_lower:0:1}"
  eval words_by_$letter+='($word)'
done </usr/share/dict/words

word="${words[$RANDOM % ${#words[@]}]}"
unset words

echo "$word"
while :; do
  word_lower="$word"
  letter="${word_lower:${#word}-1:1}"
  eval words_by_letter_num='${#words_by_'"$letter"'[@]}'
  [[ words_by_letter_num -eq 0 ]] && break
  index=$(($RANDOM % $words_by_letter_num))
  eval word='${words_by_'"$letter"'['"$index"']}'
  eval unset 'words_by_'"$letter"'['"$index"']'
  echo "$word"
done

ふつうにスクリプトになってしまった。何のひねりもない…。


ところで、12月25日はクリスマスな上に、 OSS 界隈で地味に活躍されているふみやすさんの誕生日ですね。
http://www.amazon.co.jp/registry/wishlist/27M7TV8CEEF6G?sort=priority

逆に、あなたの書いた OSS や Blog や Advent Calendar が気に入ったら何か送りたく なってしまうかもしれないので、プロフィールや Web サイトに あなたの Amazon 欲しいものリストの URL を貼っておいてくださいね!


私が勤める OSSTech っていう某弊社で社員募集しているようです。 人材紹介会社を介さなければ、入社後に 20万円のボーナス! 「ふみやすっていう人に紹介された」と言ってもらえると私にもボーナス!! → http://www.osstech.co.jp/company/recruit

バツイチでアラフォーでほとんど諦めていますが、新たなパートナーも募集中です。 ちゃんと愛情表現してくれて精神的に自立している女性がいいです。お友達から始めましょう。 → https://twitter.com/satoh_fumiyasu


よろしければ、過去の Advent Calendar もどうぞ。