labunix's blog

labunixのラボUnix

USP友の会 20131102 第7回シェル芸勉強会 を解いてみた。

■USP友の会 201311027回シェル芸勉強会 を解いてみた。
 今回を除くと、8,9回の2回分ですか。。。

 シェル芸勉強会スライド一覧
 http://blog.ueda.asia/?page_id=684

 USP友の会 201306225回シェル芸勉強を解いてみた。
 http://labunix.hateblo.jp/entry/20141014/1413298748

 USP友の会 勉強会 番外編(OSC 2013 Tokyo/Spring)を解いてみた。
 http://labunix.hateblo.jp/entry/20141013/1413129899

 「第13回危険でない方のシェル芸勉強会」を解いてみた。
 http://labunix.hateblo.jp/entry/20141005/1412439761

■それでは。

問題1
 ・ドットで区切られた4つの数字について、
  左側の数字を優先に
  数字の小さい順に並べてください。

$ cat ip
123.45.6.78
1.9.8.4
1.119.8.4
199.9.31.123
20.123.123.123
19.345.6.78

■これはノーマルに。

$ sort -t\. -n -k 1,1 -k 2,2 -k 3,3 -k 4,4 ip
1.9.8.4
1.119.8.4
19.345.6.78
20.123.123.123
123.45.6.78
199.9.31.123

問題2
 ・次の文について、tax,1km,10000の前後に半角スペースを挿入してください。

 このtaxiは1kmあたり10000円

■なんとなく「&」を使わない方法で。

$ echo "このtaxi1kmあたり10000" | \
  sed s/"\([a-z0-9][a-z0-9]*\)"/" \1 "/g
この taxi は 1km あたり 10000 円

問題3
 ・次の文についてspaceの前・invaderの後ろ・
  4の後ろのスペースを除去してください。

 私の名前は space invader です。4 歳です。

■後から楽に読めるように。

$ echo "私の名前は space invader です。4 歳です。" | \
  sed s/" \(space invader\) \(です。4\) "/"\1\2"/
私の名前はspace invaderです。4歳です。

問題4

 ・次のマーク付きの文について
 「<b>hoge</b>」が重複していることをワンライナーで示してください。

 <b>hoge</b><b>fuga</b>なので<b>hoge</b>fugaだよね。

■普通に解く。

$ echo '<b>hoge</b>は<b>fuga</b>なので<b>hoge</b>fugaだよね。' | \
  sed s%"/b>"%"&\n"%g | sed s/"<b"/"\n&"/g| grep "<" | \
  sort | uniq -c | awk '($1>1){print $2}'
<b>hoge</b>

問題5
 ・0000120000という名前の空のファイルを作ってください。

■この位は日常。

$ touch `seq -w 1 20000`
$ ls 0000* 2000*
00001  00002  00003  00004  00005  00006  00007  00008  00009  20000
$ ls [012]* | wc -l
20000

問題6
 ・a)さきほど作った2万個のファイルのリストをなるべき短い時間で作ってください。
 ・b)ファイルを消してください。

■多分意図と異なるがソートしないlsより、echoの方が速い。
 ただし、正順だが区切りは空白。

$ time echo * >/dev/null

real	0m0.086s
user	0m0.072s
sys	0m0.016s

$ time ls -f * >/dev/null

real	0m0.116s
user	0m0.072s
sys	0m0.044s

$ time echo * | xargs rm -f

real	0m0.274s
user	0m0.088s
sys	0m0.188s

問題7
 ・右下の図のようなディレクトリ、ファイルを作り、
 例えば、
  ./a/001なら./a_001
  ./b/c/123なら./b_c_123
 のようにパスの「/」をアンダースコアに変えて、
 「./」にコピーを置いてください。
 -できる人はwhileやforを使わないで

■とりあえず作るところから。

$ mkdir -p a b/c;touch a/{001,002} b/c/123 b/{xxx,yyy}

$ tree
.
├── a
│   ├── 001
│   └── 002
└── b
    ├── c
    │   └── 123
    ├── xxx
    └── yyy

3 directories, 5 files

■まあ、2回位なら。

$ find . -type f | cut -c 3- | awk '{print "cp "$0,$0";"}' | \
  sed s%"/\([a-z0-9]*;\)"%"_\1"%  | sed s%"/\([a-z0-9_]*;\)"%"_\1"% | sh
$ find . -type f | grep _
./b_yyy
./a_001
./a_002
./b_xxx
./b_c_123

問題8
 ・/etc/ 下の読み込み可能な書くファイルについて、
  fooと書いてある行の行数を数えてください。

■あれ、書くファイルの行数じゃ。。。

$ grep -r -a foo /etc/ 2>/dev/null | awk -F\: '{print $1}' | uniq -c | \
  sed s%"\( /etc/\).*"%"\1hoge"% | awk '{sum+=$1;print};END{print sum}'
      1 /etc/hoge
      2 /etc/hoge
      1 /etc/hoge
      2 /etc/hoge
      1 /etc/hoge
      5 /etc/hoge
      2 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      4 /etc/hoge
      1 /etc/hoge
      4 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      2 /etc/hoge
      3 /etc/hoge
      3 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
     14 /etc/hoge
      1 /etc/hoge
     10 /etc/hoge
     11 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
     21 /etc/hoge
      1 /etc/hoge
      2 /etc/hoge
     12 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      2 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      2 /etc/hoge
     17 /etc/hoge
      6 /etc/hoge
     12 /etc/hoge
      1 /etc/hoge
     21 /etc/hoge
      5 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      3 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
194

問題9
 ・今度は、/etc/ 下の読み込み可能な各ファイルについてfooの数を数えてください。

$ grep -r -a -o foo /etc/ 2>/dev/null | uniq -c | \
  sed s%"\( /etc/\).*"%"\1hoge"% | awk '{sum+=$1;print};END{print sum}'
      1 /etc/hoge
      2 /etc/hoge
      1 /etc/hoge
      2 /etc/hoge
      1 /etc/hoge
      8 /etc/hoge
      2 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      4 /etc/hoge
      1 /etc/hoge
      4 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      2 /etc/hoge
      4 /etc/hoge
      3 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
     20 /etc/hoge
      1 /etc/hoge
     10 /etc/hoge
     14 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
     29 /etc/hoge
      1 /etc/hoge
      4 /etc/hoge
     14 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      2 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      2 /etc/hoge
     23 /etc/hoge
      6 /etc/hoge
     15 /etc/hoge
      1 /etc/hoge
     29 /etc/hoge
      7 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      1 /etc/hoge
      3 /etc/hoge
      2 /etc/hoge
      2 /etc/hoge
240

問題10
 ・日付の古い順にソートしてください。

$ cat days 
Jan 4, 2012
Jul 19, 2013
Jul 2, 2013
Apr 9, 2010
Oct 30, 2012

■manマニュアル通りではなく、大文字小文字混在でも通るらしい。

$ man sort 2>/dev/null | grep 月名
              月名でソートする。(不明) < 'JAN' < ... < 'DEC' の順

$ cat days | tr '[a-z]' '[A-Z]'| sort -k 3,3 -k1,1M -k 2,2n | \
  sed 's/^\([A-Z]\)\(.*\)/\1\L\2/'
Apr 9, 2010
Jan 4, 2012
Oct 30, 2012
Jul 2, 2013
Jul 19, 2013

$ sort -k 3,3 -k1,1M -k 2,2n days
Apr 9, 2010
Jan 4, 2012
Oct 30, 2012
Jul 2, 2013
Jul 19, 2013