【問題と解答例】第13回危険でない方のシェル芸勉強会
Sat Oct 4 15:10:55 JST 2014 (modified: Sun Oct 1 10:50:27 JST 2017)
views: 5098, keywords:CLI,Linux,Mac,Unix,勉強会,シェル芸,シェル芸勉強会 この記事は最終更新日が7年以上前のものです。
環境
Macで解答を作ったのでLinuxな方は次のようにコマンドの読み替えを。
Mac,BSD系 | Linux |
---|---|
gdate | date |
gsed | sed |
tail -r | tac |
gtr | tr |
gfold | fold |
Q1
次のようにShift JISのファイルを作り、Shift JISで「きく」と書いてあるファイルを探すワンライナーを考えてください。(答えは「b」ですね。)
uedambp:q1 ueda$ echo あいうえお | nkf -xLws > a
uedambp:q1 ueda$ echo かきくけこ | nkf -xLws > b
uedambp:q1 ueda$ echo さしすせそ | nkf -xLws > c
解答
uedambp:q1 ueda$ for f in * ; do nkf -w $f | grep -q きく && echo $f ; done
b
Q2
次のようにディレクトリa,b,c,dに1,2,...,9というファイルがあります。各ディレクトリ内のファイル数をワンライナーで数えてください。
uedambp:q2 ueda$ tree
.
a
├── 1
│ ├── 2
│ ├── 3
│ └── b
├── 4
│ ├── 5
│ └── c
├── d
└── 6
├── 7
├── 8
├── 9 └──
解答
uedambp:q2 ueda$ find . | tr / ' ' | awk 'NF==3{print $2}' | uniq
c- 3 a
2 b
4 d
uedambp:q2 ueda$ find . -type f | awk -F/ '{print $2}' | uniq
c- 3 a
2 b
4 d
###cも出したければ・・・###
uedambp:q2 ueda$ find . | awk -F/ '{print $2}' |
uniq -c | awk 'NF==2{print $2,$1-1}'
a 3
b 2
c 0
d 4
uedambp:q2 ueda$ ls * | xargs | gsed 's/.:/\\n&/g' | awk '{print $1,NF-1}'
-1
a: 3
b: 2
c: 0
d: 4
uedambp:q2 ueda$ ls -d * |
while read d ; do echo -n $d" " ; ls $d | gyo ; done
a 3
b 2
c 0
d 4
Q3
今度は次のような配置でファイル1,2,...,9が置かれているときに、ワンライナーでa、cの下のファイルの総数をカウントしてください(ディレクトリを除く)。つまりaなら5個、cなら4個が正解です。
uedambp:q3 ueda$ tree
.
a
├── 1
│ ├── 2
│ ├── 3
│ ├── b
│ └── 4
│ ├── 5
│ └── c
└── d
└── 6
├── 7
├── 8
├── 9 └──
解答
uedambp:q3 ueda$ find . -type f | awk -F/ '{print $2}' | uniq
c- 5 a
4 c
Q4
まず、次のように8桁日付のファイルを作ります。
uedambp:q4 ueda$ seq -w 1 31 | xargs -I@ touch 201401@
uedambp:q4 ueda$ ls
20140101 20140107 20140113 20140119 20140125 20140131
20140102 20140108 20140114 20140120 20140126
20140103 20140109 20140115 20140121 20140127
20140104 20140110 20140116 20140122 20140128
20140105 20140111 20140117 20140123 20140129
20140106 20140112 20140118 20140124 20140130
曜日別にディレクトリを作り、その中に当該するファイルを放り込んでください。
解答
uedambp:q4 ueda$ ls | gdate -f - '+%Y%m%d %a' |
while read d w ; do mkdir -p $w ; mv $d $w ; done
###英語のディレクトリにする###
uedambp:q4 ueda$ ls | LANG=C gdate -f - '+%Y%m%d %a' |
while read d w ; do mkdir -p $w ; mv $d $w ; done
Q5
以下のようにa,b,cというディレクトリを作り、その下に「{a,b,c}数字」というファイルを作ります。ファイル名の1文字目とディレクトリ名が一致するようにファイルを移動してください。
uedambp:q5 ueda$ tree
.
a
├── a01
│ ├── b01
│ └── b
├── a02
│ ├── a03
│ ├── c01
│ └── c
└── a04 └──
解答
uedambp:q5 ueda$ find . -type f |
awk '{print "mv",$1,substr($1,5,1)}' | sh
mv: ./a/a01 and a/a01 are identical ←エラーが出るけど大丈夫
uedambp:q5 ueda$ tree
.
a
├── a01
│ ├── a02
│ ├── a03
│ ├── a04
│ └── b
├── b01
│ └── c
└── c01 └──
Q6
次のようにディレクトリa, b, cの下に、8桁日付のファイルをいくつか置きます。
uedambp:q6 ueda$ tree
.
a
├── 20130120
│ ├── 20140901
│ ├── 20141021
│ └── b
├── 20131011
│ ├── 20140202
│ └── c
└── 20110202
├── 20130224
├── 20141224 └──
各ディレクトリの最新日付のファイルをカレントディレクトリ(a,b,cのあるディレクトリ)にコピーしてください。各ディレクトリの最新ファイルの日付はそれぞれ違い、コピーの際に衝突しないこととします。
解答
uedambp:q6 ueda$ for d in * ; do ls $d | tail -n 1 |
xargs -n 1 -I@ cp $d/@ ./ ; done
###確認###
uedambp:q6 ueda$ ls
20140202 20141021 20141224 a b c
uedambp:q6 ueda$ find . -type f | tr '/' ' ' |
awk '{f[$2]=f[$2]<$3?$3:f[$2]}END{for(k in f){print k,f[k]}}' |
tr ' ' '/' | xargs -n 1 -I@ cp @ ./
###Tukubai等###
uedambp:q6 ueda$ find . -type f | tr '/' ' ' | sort | getlast 1 2 |
tr '/' ' ' | awk '{print "cp", "./" $2 "/" $3 " ./"}' | sh
Q7
Q6について、適当にファイルをtouchします。今度はタイムスタンプが最新のファイルを、a, b, cそれぞれからカレントディレクトリにコピーしてください。コピーの際にタイムスタンプを変えない事。
解答
uedambp:q7 ueda$ for d in * ; do ls -t $d | head -n 1 |
xargs -I@ -n 1 cp -p $d/@ ./ ; done
Q8
次のように5個ファイルを作ります。file1をfile2, file2をfile3, file3をfile4, file4をfile5, file5をfile1にmvしてください。
uedambp:q8 ueda$ for i in 1 2 3 4 5 ; do echo $i > file$i ; done
uedambp:q8 ueda$ head *
> file1 <==
==1
> file2 <==
==2
> file3 <==
==3
> file4 <==
==4
> file5 <==
==5
解答
uedambp:q8 ueda$ ls |
awk 'BEGIN{a="tmp"}{print a,$1;a=$1}END{print a,"tmp"}' |
tail -r | awk '{print "mv",$1,$2}' | sh
uedambp:q8 ueda$ head *
> file1 <==
==5
> file2 <==
==1
> file3 <==
==2
> file4 <==
==3
> file5 <==
==4