【問題と解答例】第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
ノート   このエントリーをはてなブックマークに追加 
 

prev:【問題のみ】第13回危険でない方のシェル芸勉強会 next:布団の中でiPhoneを使ってLaTeXの文章を書く手法の提案

やり散らかし一覧

記事いろいろ