Skip to content

Instantly share code, notes, and snippets.

@papiron
Last active March 13, 2016 09:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save papiron/f256f09e5a6ddde1d28f to your computer and use it in GitHub Desktop.
Save papiron/f256f09e5a6ddde1d28f to your computer and use it in GitHub Desktop.
シェルスクリプト入門福岡の解答例
2016/03/11 (金) に開催された「シェルスクリプト入門 福岡」の別解です。
https://atnd.org/events/75045
問題とデータは下記を参照のこと
https://github.com/ShuyaMotouchi/shellstadyQ
Tukubaiコマンドは下記を参照のこと。
https://uec.usp-lab.com/TUKUBAI/CGI/TUKUBAI.CGI?POMPA=LIST
これらの解き方はあくまでも例に過ぎません。他にも色々なやり方があるので考えてみよう。
解答例はMacを利用。GNU版のdateやsedは、gdateとgsedになっているので注意。
Linuxの人はgdateとgsedをdateとsedで読み替えてください。
この解答例は、USP友の会主催のシェル芸勉強会で培ったノウハウによるものです。
https://www.usptomo.com
Q01
test.txtの文字数を数えてください!!!出来る人はより変態に数えてください!!
$ cat test.txt | tr -d ' \n' | wc -m
10039
$ cat test.txt | tr -d ' \n' | grep -o . | wc -l
10039
$ cat test.txt | tr -d ' \n' | awk '{print length($0)}'
10039
$ cat test.txt | tr -d ' ' | awk '{print length($0)}' | awk '{sum+=$0}END{print sum}'
10039
$ cat test.txt | tr -d ' ' | sed 's/./& /g' | awk '{print NF}' | awk '{sum+=$1}END{print sum}'
10039
numsumはbrew install num-utilsでインストール(Perlスクリプト群)
$ cat test.txt | tr -d ' ' | awk '{print length($0)}' | numsum
10039
$ cat test.txt | tr -d ' ' | sed 's/./& /g' | awk '{print NF}' | numsum
10039
Tukubaiコマンド利用
$ cat test.txt | tr -d ' ' | sed 's/./& /g' | awk '{print NF}' | sm2 0 0 1 1
10039
以下は全てマルチバイト文字の場合限定(1文字3バイトの前提)
xxdコマンドはvimに付属のバイナリダンプコマンド。
環境変数LANGがja_JP.UTF-8の必要有。
$ cat test.txt | tr -d ' \n' | xxd -p | tr -d '\n' | gsed 's/....../&\n/g' | wc -l
10039
$ cat test.txt | tr -d ' \n' | xxd -p | tr -d '\n' | grep -o ...... | wc -l
10039
Q02
シェルプログラミング実用テクニックは8章構成になっており
文章をまとめるために章毎にディレクトリーを作りたいが面倒なのでワンライナーで完成させたい!!!
この8つのディレクトリさえあれば良い!!
シェルプログラミング実用テクニック01章
シェルプログラミング実用テクニック02章
シェルプログラミング実用テクニック03章
シェルプログラミング実用テクニック04章
シェルプログラミング実用テクニック05章
シェルプログラミング実用テクニック06章
シェルプログラミング実用テクニック07章
シェルプログラミング実用テクニック08章
【bash ver4のみ】
$ mkdir シェルプログラミング実用テクニック{01..08}章
$ for n in {01..08}; do echo "シェルプログラミング実用テクニック"$n"章";done
seqコマンドで数字を列挙してから
$ seq 1 8 | sed 's/^/0/' | while read n; do mkdir "シェルプログラミング実用テクニック"$n"章"; done
$ seq 1 8 | awk '{printf "シェルプログラミング実用テクニック%02d章\n",$0}' | xargs mkdir
$ seq -f '%02.0f' 8 | sed 's/.*/シェルプログラミング実用テクニック&章/' | xargs mkdir
$ seq 1 8 | xargs printf "シェルプログラミング実用テクニック%02d章\n" | xargs mkdir
Q03
test.txtの中からメロスという単語の数を数えてくれ!!!
$ cat test.txt | grep -o メロス | wc -l
76
Q04
test.txtのメロスを全員「もとうち」に名前に変換して出力せよ!!!
×出来る方は現在、ログインしているユーザーの名前に変えて出力して下さい!!
$ cat test.txt | sed "s/メロス/もとうち/g"
$ cat test.txt | sed "s/メロス/`whoami`/g"
$ cat test.txt | sed "s/メロス/$(whoami)/g"
Q05
/home 以下から現在、ログインしているユーザーの名前を含むファイルを全て列挙して下さい。
×少し難しい(シェル芸やってないと考え方が)ので飛ばしてもどうぞ!!
ログインユーザ名の文字列が含まれるファイルの列挙ということかな?
$ grep -rl `whoami` /home
Macな人だと/Users以下とかの方がいいかも
$ grep -rl `whoami` /Users
/Users/tashiro/.android/adbkey.pub
/Users/tashiro/.atom/.apm/.apmrc
/Users/tashiro/.atom/compile-cache/coffee/f55c001218bab56807639b76ab1aba348a7517f1.js
/Users/tashiro/.atom/storage/application.json
/Users/tashiro/.atom/storage/editor-0bb16aea324920774233b8b42594d0cd4d1c7eae
/Users/tashiro/.atom/storage/editor-31f79d0cadf44600c8dba38a4508c739eb712b32
/Users/tashiro/.atom/storage/editor-ac1dd619274fc2e0887286782fb728005176bbd7
/Users/tashiro/.atom/storage/editor-cb400d256f87a617231dd01de3606bbc1b982ab4
/Users/tashiro/.atom/storage/editor-ccc56c1045bb938d76fcc3d5f2ac866daed5ff1e
/Users/tashiro/.bitclust/config
補足
ファイル名とファイルの中身をセットで出力するならこんな感じ。
$ grep -r '' /home
$ find /usr/home -type f | xargs awk '{print FILENAME,$0}'
Q06
全ユーザーとホームディレクトリのみを列挙して下さい
hint:/etc/passwd
$ cat /etc/passwd | grep -o '^[^#]*' | sed '/^$/d' | awk -F: '{print $1,$(NF-1)}'
Tukubaiコマンド使用(self)
$ cat /etc/passwd | grep -o '^[^#]*' | sed '/^$/d' | tr ':' ' ' | self 1 NF-1
Q07
コマンド使用回数ランキングのトップ10を使用回数と一緒に
表示させよ。
今回はls ls -a は別のコマンドとして扱う!!
historyから集計すればいい?
$ history | awk '{for(i=2;i<=NF;i++){printf "%s ",$i}print ""}' | sort | uniq -c | sort -k1,1nr | head
$ history | awk '{$1="";print}' | sort | uniq -c | sort -k1,1nr | head
Tukubaiコマンド使用(delf)
$ history | delf 1 | sort | uniq -c | sort -k1,1nr | head
Q08
入門(普通の人)
プロセスのうちログインユーザが動かしているものだけを
出力して下さい
ps auxwwで全ユーザのプロセスを出したという前提で
$ ps auxww | awk '$1=="'$(whoami)'"{for(i=11;i<=NF;i++)printf "%s ",$i;print ""}'
Tukubaiコマンド使用(self)
$ ps auxww | awk '$1=="'$(whoami)'"' | self 11/NF
解けるもんなら解いてみろ!!!(変態用)
ログインユーザが動かしているプロセスのうち、メモリの使用率が
高いものから順番にPIDを10個出力してください
ps auxwwで全ユーザのプロセスを出したという前提
$ ps auxww | awk '$1=="'$(whoami)'"' | sort -k4,4nr | head | awk '{for(i=11;i<=NF;i++)printf "%s ",$i;print ""}'
Tukubaiコマンド利用
$ ps auxww | awk '$1=="'$(whoami)'"' | sort -k4,4nr | head | self 11/NF
Q09
bashを使っているユーザーのログインシェルをbashからzshに変更する。
実際には書き込まなくても良い!!!
というか書き込まないでくれ!!!!
こんな感じ??
$ cat /etc/passwd | sed 's/bash$/zsh/'
Q10
初心者のボス問題として作りました。
問題はそんなに難しくないです。
ワンライナーでtest.txtと似たような文章を出力して下さい。
hint my blog
awk芸
$ seq 20 | awk 'NR%2{print $0,"奇数"}NR%2==0{print $0,"偶数"}' | awk 'NR%5{printf $0" "}NR%5==0{print}'
$ seq 20 | awk 'NR%2{print $0,"奇数"}NR%2==0{print $0,"偶数"}' | xargs -n 10
$ seq 1 20 | xargs -n 5 | awk '{for(i=1;i<=NF;i++)if($i%2==0){sub(/$/," 偶数",$i)}else{sub(/$/," 奇数",$i)};print}'
sed芸
$ seq 20 | gsed '1~2s/$/ 奇数/' | gsed '0~2s/$/ 偶数/' | xargs -n 10
補足
xargsで並べかえする場合、データが多いと遅い。
awkやTukubaiコマンドのyarrを使う方が高速。
Q11
2016年の日曜日を全て列挙してください。
日付の場合はdateコマンドを使おう。GNU版とBSD版でオプションなどが異なる。
とりあえずdateコマンドを366回実行する。(なので処理は遅い)
GNU dateの場合
$ seq 0 365 | xargs -I@ gdate -d '20160101 @ day' '+%Y%m%d %a' | grep '日$'
BSD dateの場合
$ seq 0 365 | xargs -I@ date -v+@d -j -f '%Y%m%d' 20160101 '+%Y%m%d %a' | grep '日$'
少し無駄をなくす。日曜日は7日毎なので下記のやり方でも良い
GNU dateの場合
$ seq 2 7 365 | xargs -I@ gdate -d '20160101 @ day' '+%Y%m%d %a'
BSD dateの場合
$ seq 2 7 365 | xargs -I@ date -v+@d -j -f '%Y%m%d' 20160101 '+%Y%m%d %a'
GNU dateコマンドで荒っぽい解き方。
日付もどきの一覧を標準入力から食わせる。不正な日付はエラー出力されるので捨て去る。
dateコマンドは一回だけ実行なので処理は速い。
$ seq -w 0101 1231 | sed 's/^/2016/' | gdate -f - "+%Y%m%d %a" 2> /dev/null | grep '日$'
Tukubaiのmdateコマンドなどを使うと、高速で簡潔に処理が出来る。
$ mdate -e 20160101 20161231 | tarr | yobi -j 1 | grep '日$'
Q12
fizzBuzz
オーソドックスな解答
$ seq 1 20 | awk '$1%3==0{printf "Fizz"}$1%5==0{printf "Buzz"}{print " " $1}' | awk '{print $1}'
ちょっと頭おかしいsed芸
$ seq 1 20 | gsed '5~5s/.*/Buzz/' | gsed '3~3s/[0-9]*/Fizz/' (GNU sedのみ)
$ seq 1 20 | sed 'n;n;s/.*/Fizz/' | sed 'n;n;n;n;s/[0-9]*$/Buzz/'
$ seq 1 20 | sed 'n;n;s/.*/Fizz/' | sed 'n;n;n;n;/F/s/$/Buzz/;/F/!s/.*/Buzz/'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment