labunix's blog

labunixのラボUnix

「第13回危険でない方のシェル芸勉強会」を解いてみた。

■「第13回危険でない方のシェル芸勉強会」を解いてみた。

 【問題と解答例】第13回危険でない方のシェル芸勉強会
 http://blog.ueda.asia/?p=3792

■過去14回分が下記にあります。

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

$ w3m -dump "http://blog.ueda.asia/?page_id=684" | \
  grep "^[0-9]*\|^番外編" | \
  awk '{print};END{print "全"NR"回"}'13回
第12回
第11回
第10回
第9回
第8回
第7回
第6in LLまつり
第5回
第4回
番外編(OSC 2013 Tokyo/Spring)
第3回
第2回
第1回
全14回

■私も暇なのか、結構解いてます。。。

 第12回本当は怖くないシェル芸勉強会」を解いてみた
 http://labunix.hateblo.jp/entry/20140803/1407076184

 ※第11回
 jus & USP友の会共催 シェルワンライナー勉強会@関西(第11回シェル芸勉強会)」を解いてみた。
 http://labunix.hateblo.jp/entry/20140616/1402927517

 第10回シェル芸勉強会」を解いてみた。
 http://labunix.hateblo.jp/entry/20140930/1412085463

 ※第6回
 「LLまつりでシェル芸人をジェネレートしてきた」を参加していないのに解いてみた。
 http://labunix.hateblo.jp/entry/20130915/1379249444

 ※第4回
 413日、渋谷でシェル芸勉強会に参加していないのに解いてみた。
 http://d.hatena.ne.jp/labunix/20130414

 ※第4回 勝手に予習編
 USP友の会「413日、渋谷でシェル芸勉強会」の予習をしたい方向け
 http://d.hatena.ne.jp/labunix/20130325

 ※第3回
 「シェル芸爆破デスマッチ勉強会」に参加してないのに解いてみた
 http://d.hatena.ne.jp/labunix/20130217

 第2回チキチキ! シェル芸人養成勉強会 参加報告
 http://d.hatena.ne.jp/labunix/20121209

 ※第1回
 USP友の会会長が出題した前半戦を解いてみた。
 http://d.hatena.ne.jp/labunix/20121111

 USP友の会会長が出題した後半戦を解いてみた。
 http://d.hatena.ne.jp/labunix/20121112

■それでは始めましょう。

Q1. 次のようにShift JISのファイルを作り、
    Shift JISで「きく」と書いてあるファイルを探すワンライナーを考えてください。
    (答えは「b」ですね。)

$ echo あいうえお | nkf -xLws > a
$ echo かきくけこ | nkf -xLws > b
$ echo さしすせそ | nkf -xLws > c

■ファイル名を一緒に出してしまえば簡単。

$ grep . [abc] | nkf -Lw | grep きく | awk -F\: '{print $1}'
b

Q2. 次のようにディレクトリa,b,c,dに1,2,…,9というファイルがあります。
    各ディレクトリ内のファイル数をワンライナーで数えてください。

■まずはtree構造を作るところから。

$ mkdir {a,b,c,d}; \
  touch a/{1,2,3}  b/{4,5} d/{6,7,8,9}

$ tree 
.
├── a
│   ├── 1
│   ├── 2
│   └── 3
├── b
│   ├── 4
│   └── 5
├── c
└── d
    ├── 6
    ├── 7
    ├── 8
    └── 9

4 directories, 9 files


$ find . -type f | awk -F\/ '{print $2}' | uniq -c
      4 d
      2 b
      3 a

■解答例と同じだったので、findもlsも使わないパターン。。。

$ echo */* | sed s/" \|\/[0-9]"/"\n"/g | grep -v "^\$" | sort | uniq -c
      3 a
      2 b
      4 d

Q3.今度は次のような配置でファイル1,2,…,9が置かれているときに、
   ワンライナーでa、cの下のファイルの総数をカウントしてください
   (ディレクトリを除く)。つまりaなら5個、cなら4個が正解です。

■これも作るところから。

$ mkdir -p a/b c/d; \
  touch a/{1,2,3} a/b/{4,5} c/d/{6,7,8,9}; \
  tree
.
├── a
│   ├── 1
│   ├── 2
│   ├── 3
│   └── b
│       ├── 4
│       └── 5
└── c
    └── d
        ├── 6
        ├── 7
        ├── 8
        └── 9

4 directories, 9 files

$ find . -type f | cut -c 3-3 | uniq -c
      5 a
      4 c

Q4.まず、次のように8桁日付のファイルを作ります。

$ seq -w 1 31 | xargs -I@ touch 201401@
$ ls | column -c 80
20140101	20140108	20140115	20140122	20140129
20140102	20140109	20140116	20140123	20140130
20140103	20140110	20140117	20140124	20140131
20140104	20140111	20140118	20140125
20140105	20140112	20140119	20140126
20140106	20140113	20140120	20140127
20140107	20140114	20140121	20140128

 曜日別にディレクトリを作り、その中に当該するファイルを放り込んでください。

■英語パターンで。

$ for list in 2*;do \
    TARGET=`env LANG=C date -d "$list" '+%a'`; \
    test -d "$TARGET" || mkdir "$TARGET"; \
    mv "$list" "$TARGET"; \
  done

$ tree
.
├── Fri
│   ├── 20140103
│   ├── 20140110
│   ├── 20140117
│   ├── 20140124
│   └── 20140131
├── Mon
│   ├── 20140106
│   ├── 20140113
│   ├── 20140120
│   └── 20140127
├── Sat
│   ├── 20140104
│   ├── 20140111
│   ├── 20140118
│   └── 20140125
├── Sun
│   ├── 20140105
│   ├── 20140112
│   ├── 20140119
│   └── 20140126
├── Thu
│   ├── 20140102
│   ├── 20140109
│   ├── 20140116
│   ├── 20140123
│   └── 20140130
├── Tue
│   ├── 20140107
│   ├── 20140114
│   ├── 20140121
│   └── 20140128
└── Wed
    ├── 20140101
    ├── 20140108
    ├── 20140115
    ├── 20140122
    └── 20140129

7 directories, 31 files

Q5.以下のようにa,b,cというディレクトリを作り、その下に「{a,b,c}数字」という
   ファイルを作ります。ファイル名の1文字目とディレクトリ名が一致するように
   ファイルを移動してください。

■これもつくるところから。

$ mkdir {a,b,c}; \
  touch a/{a01,b01} b/{a02,a03,c01} c/a04; \
  tree
.
├── a
│   ├── a01
│   └── b01
├── b
│   ├── a02
│   ├── a03
│   └── c01
└── c
    └── a04

$ for n in a b c;do mv */${n}[0-9]* ${n};done
mv: 'a/a01''a/a01' は同じファイルです
$ tree
.
├── a
│   ├── a01
│   ├── a02
│   ├── a03
│   └── a04
├── b
│   └── b01
└── c
    └── c01

3 directories, 6 files


Q6.次のようにディレクトリa, b, cの下に、8桁日付のファイルをいくつか置きます。
   各ディレクトリの最新日付のファイルをカレントディレクトリ
   (a,b,cのあるディレクトリ)にコピーしてください。
   各ディレクトリの最新ファイルの日付はそれぞれ違い、コピーの際に衝突しない
   こととします。

■今回はつくるのが多いですね。。。

$ mkdir {a,b,c}; \
  touch a/{20130120,20140901,20141021} \
        b/{20131011,20140202} \
        c/{20110202,20130224,20141224}

$ tree 
.
├── a
│   ├── 20130120
│   ├── 20140901
│   └── 20141021
├── b
│   ├── 20131011
│   └── 20140202
└── c
    ├── 20110202
    ├── 20130224
    └── 20141224

3 directories, 8 files

$ for n in a b c;do cp "${n}/`ls -na $n | tail -1 | awk '{print $NF}'`" .;done
$ tree
.
├── 20140202
├── 20141021
├── 20141224
├── a
│   ├── 20130120
│   ├── 20140901
│   └── 20141021
├── b
│   ├── 20131011
│   └── 20140202
└── c
    ├── 20110202
    ├── 20130224
    └── 20141224

3 directories, 11 files

Q7.Q6について、適当にファイルをtouchします。今度はタイムスタンプが最新の
   ファイルを、a, b, cそれぞれからカレントディレクトリにコピーしてください。
   コピーの際にタイムスタンプを変えない事。

$ touch a/2013* c/2011*
$ find . -type f -mtime -0.002 -exec cp -p {} . \;
$ ls -l 201[13]* [ac]/{20110202,20130120} | awk '{print $(NF-1),$NF}'
01:04 20110202
01:04 20130120
01:04 a/20130120
01:04 c/20110202

Q8.次のように5個ファイルを作ります。file1をfile2, file2をfile3, 
   file3をfile4, file4をfile5, file5をfile1にmvしてください。

$ for i in 1 2 3 4 5 ; do echo $i > file$i ; done
$ grep . file*
file1:1
file2:2
file3:3
file4:4
file5:5

■難しく考えない方が良い。

$ for n in `seq 5 -1 1`;do mv "file$n" "file$(($n+1))";done;mv file6 file1

$ grep . file*
file1:5
file2:1
file3:2
file4:3
file5:4