2016/10/17

シェル芸スパルタン演習(第10回シェル芸勉強会編)

ここ最近、Unixシェルに触る機会が減っており、CLIを使う能力の低下を感じていた。
また、近日中に、第25回シェル芸勉強会の開催が予定されており、参加するにあたり予習をしたいとも考えていた。
そこで、過去に開催されたシェル芸勉強会の問題を活用し、シェル芸力をつける演習をおこなうことにした。

今回は、問題として、第10回シェル芸勉強会の設問を用いた。


実行環境

  • Arch Linux 4.8.4-1-ARCH

  • GNU bash 4.3.46

  • GNU coreutils 8.25-2

  • GNU diffutils 3.5-1

  • GNU findutils 4.6.0-2

  • util-linux 2.28.2-1

  • grep (GNU grep) 2.26

  • GNU bc 1.06.95

  • sed (GNU sed) 4.2.2

  • gawk 4.1.4


シェル芸演習

問題文は、以下のURLから。
https://blog.ueda.asia/?p=2627

模範解答は、こちらから。
http://blog.ueda.asia/?p=2378

問1

ファイルの中身の数値を足し合わせる問題。

式を作って、bcにぶち込む。

01 #!/bin/sh
02
03 echo 2 5 9 8 1 3 7 4     |
04 tr ' ' '+'               |
05 bc

Tukubaiのplusコマンドで。

01 #!/bin/sh
02
03 plus $(echo 2 5 9 8 1 3 7 4)

以下、コピペ実行用のワンライナーコード。

echo 2 5 9 8 1 3 7 4 | tr ' ' '+' | bc
plus $(echo 2 5 9 8 1 3 7 4)

問2

中身にゴミスペースが混じっているファイルのうち、数字を足し合わせる問題。

ゴミを除去した後、式を作ってbcへ入れる。

01 #!/bin/sh
02
03 cat nums       |
04 xargs          |
05 tr ' ' '+'     |
06 bc

Tukubaiのplusで。

01 #!/bin/sh
02
03 cat nums     |
04 xargs plus

以下、コピペ実行用のワンライナーコード。

cat nums | xargs | tr ' ' '+' | bc
cat nums | xargs plus

問3

文字数を数える問題。
1文字1レコードにした後、行数を数えるだけ。
(ただし、不要な改行は除去しておく)

01 #!/bin/sh
02
03 cat genkou     |
04 tr -d '\n'     |
05 grep -o .      |
06 wc -l

以下、コピペ実行用のワンライナーコード。

cat genkou | tr -d '\n' | grep -o . | wc -l

問4

文字列の中から、同じ文字が3つ連続する部分を抽出する問題。
grepで後方参照を使えばOK。

01 #!/bin/sh
02
03 cat hoge                |
04 grep -o '\(.\)\1\1'     |
05 awk -vFS= '$0=$1'

以下、コピペ実行用のワンライナーコード。

cat hoge | grep -o '\(.\)\1\1' | awk -vFS= '$0=$1'

問5

ディレクトリツリーの中から、ファイルをカレントに移動してくる問題。

findでファイルのみを列挙した後、xargs mvするだけ。

01 #!/bin/sh
02
03 find ./a -type f     |
04 xargs -I@ mv @ ./

別解。xargsの代わりに、mvコマンド列を生成するだけ。

01 #!/bin/sh
02
03 find ./a -type f        |
04 sed 's;.*;mv & ./;'     |
05 sh

以下、コピペ実行用のワンライナーコード。

find ./a -type f | xargs -I@ mv @ ./
find ./a -type f | sed 's;.*;mv & ./;' | sh

問6

ファイルの中身を見て、ディレクトリに分類する問題。

まず、grepでファイル名を中身と共に出力する。
その後、awkでmvコマンド列を生成する。

01 #!/bin/sh
02
03 grep '.*' ./file?                                                      |
04 awk -F: '/hoge/{print "mv",$1,"./a"} !/hoge/{print "mv",$1,"./b"}'     |
05 sh

以下、コピペ実行用のワンライナーコード。

grep '.*' ./file? | awk -F: '/hoge/{print "mv",$1,"./a"} !/hoge/{print "mv",$1,"./b"}' | sh

問7

2つのファイルの組み合わせを、組み合わせの重複無しで列挙する問題。

awkの連想配列を活用し、重複しているかどうかを判別する。

01 #!/bin/sh
02
03 ls file?                                                                     |
04 awk '{f[NR]=$1} END{for(i=1;i<=NR;i++){for(j=1;j<=i;j++){print f[j],f[i]}}}' |
05 awk '$1!=$2'

Tukubaiのloopxを使った別解。
上の解答とあまり変わらないかも。

01 #!/bin/bash
02
03 loopx <(ls file?) <(ls file?)                                        |
04 awk '{printf("%s", comb[$2,$1]==0 ? $0"\n" : ""); comb[$1,$2]++}'    |
05 awk '$1!=$2'

以下、コピペ実行用のワンライナーコード。

ls file? | awk '{f[NR]=$1} END{for(i=1;i<=NR;i++){for(j=1;j<=i;j++){print f[j],f[i]}}}' | awk '$1!=$2'
loopx <(ls file?) <(ls file?) | awk '{printf("%s", comb[$2,$1]==0 ? $0"\n" : ""); comb[$1,$2]++}' | awk '$1!=$2'

問8

特定の範囲にある数値をランダムに出力する問題。

whileるなり、yesるなり、何なり。

1 #!/bin/sh
2
3 while :; do
4     (seq 0 999999 |shuf |head -n 1)
5 done

Tukubai版。
入力から乱数を発生させるコマンド、そのまんまな名前のransuコマンドを使った。

01 #!/bin/sh
02
03 yes 'seq 0 999999 |ransu 1'     |
04 sh

以下、コピペ実行用のワンライナーコード。

while :; do (seq 0 999999 |shuf |head -n 1); done
yes 'seq 0 999999 |ransu 1' | sh

雑記

  • オオカミ可愛い🐺(書くネタが無い)

Tags: シェル芸 Unix
このエントリーをはてなブックマークに追加