Skip to content

Latest commit

 

History

History
392 lines (268 loc) · 8.17 KB

30knocks.md

File metadata and controls

392 lines (268 loc) · 8.17 KB

SoftwareDesign 2017.01 shell 30 knocks.

Q1 Catch

.exe という拡張子を持つファイルを抜き出す。

$ grep -R '\.exe$' files.txt
$ awk '/\.exe$/' files.txt
$ cat files.txt | ruby -ne 'print if /\.exe$/'

\.exe$ を使うのがポイント files.txt http://bit.ly/2iqCqdd

Q2 Catch

poolの項目にあるIPもしくはホスト名を抽出。コメント行は対象外。

$ cat ntp.conf | awk '/^pool/ {print $2}'
$ ruby -nae 'puts $F[1] if /^pool/' ntp.conf

コメント行の除外はいらないんじゃないか。 ntp.conf http://bit.ly/2iqG33c

Q3 Through

$ cat du.s | sort -nr | awk '{print $2}' | xargs du -sh

xargs を使ってやり直すのか。なるほど。

Q4 Catch

$ ls -l /bin/ | ruby -nae 'print $_ if $F[0] =~ /s/'
$ ls -l /bin/ | awk '$1~/s/'

ruby 使えたらほぼなんでもできそうな気がしてきた。 awk '$1~/s/' これやりたかったけどできんかった。 s の存在も意味も初めて知った。

Q5 Catch

$ cat log_range.log | sed -n -e '/24\/Dec\/2016 21/,/25.*2016 03/p'
$ cat log_range.log | ruby -ne 'p=true if ~/24\/Dec\/2016 21/; print if p; p=false if ~/25\/Dec\/2016 03/'
$ cat log_range.log | ruby -ne 'print if /24\/Dec\/2016 21/../25\/Dec\/2016 03/' # これでいける

awk でもできるのか!

log_range.log http://bit.ly/2ih96JR

Q6 Through

$ find . | awk -F'/' '{ c[$2] +=1} END{ for(i in c){ print i, " " c[i]} }'`

ぜんぜんちがった。

# answer
$ find . -type d | while read d; do echo -n $d" "; find "$d" -type f -maxdepth 1 | wc -l; done

while read f; do command $f ; done のイディオムをうまく使う。 -type -maxdepth のオプションを知った。

Q7 Catch

$ ps aux | awk '(NR>1) { c[$1]+=$3; m[$1]+=$4 } END{ for(i in c) print i, c[i], m[i] }' | sort -rn -k2,3

プロセスの件数をカウントしてもよい。

Q8 Through

$ wget example.com/big_file.tar.gz && mail -s 'Success' my.mail@example.com <<< '' || mail -s 'Failed.' my.mail@example.com <<< ''

さっぱりわからなかった。 && || はbash演算子で終了ステータスを判定する。

Q9 Catch?

$ tailf access.log | awk '($9==500){print}{fflush()} | xargs -I_ mail -s '500 Fail.' my.mail@example.com <<< "_"

& でバックグラウンドにすると良い。mail がうまく動かず未確認。たぶん動くと思う。
tailfawkgrep などバッファしないオプションのあるコマンドを使わないといけないようだ。

Q10 Through

これは無理

$ openssl s_client -host twitter.com -port 443 < /dev/null 2> /dev/null | openssl x509 -text | grep 'Not After'

openssl コマンド使ったことありません。

Q11 Through

これもわからない

$ echo '@reboot /bin/sleep 180 && /sbin/poweroff' | sudo crontab

Q12 Catch

bash 自体はよくわからんがなんとか。

$ seq 1 100 | while read n; do sleep 1 ; echo "羊が$n"; done
#!/bin/bash

n=1
while [ $n -le 100 ]
do
  echo -e "羊が$n"
  n=$((n + 2))
  sleep 1
done

[test の別名でオプションを覚えるといい。
$(( 3 * 8 )) 算術式展開
$(seq 1 10) コマンド置換

Q13 Catch

$ echo -e '\U1F37A' '\U1F363'

Q14 Through

$ set | grep VER

zshだとsetの出力をgrepできない。なんでだろう。

Q15 Catch

#!/bin/bash

function double () {
	for n in $@ ; do
		echo -n $(( n * 2 )) ' '
	done
	echo
}

if [ -p /dev/stdin ] ; then
	double $( cat /dev/stdin )
else
	double $@
fi

bashプログラミング慣れない。

#!/bin/bash
num=${1:-$(cat)}
echo $(( $num * 2 ))

:- := :+ :? とか分からない。 http://qiita.com/bsdhack/items/597eb7daee4a8b3276ba

Q16 Catch

$ rm -rf ./~
$ rm -rf ./-Rf

-- でオプション打ち止めとなる。

$ rm -rf -- -Rf

Q17 Through

$ while read f; do echo $f; done  < /etc/passwd > ~/a
$ echo "$(</etc/passwd)" > ~/a

リダイレクトとコマンド置換を使えばファイルを読めるのか。すごいな。

Q18 Catch

$ echo 'i am a perfect human' | tr "[:lower:]" "[:upper:]"
$ echo pen-pineapple-apple-pen | sed -e 's/^p/P/' | sed -e 's/-p/-P/g' | sed -e 's/-a/-A/g'

一応出来たけど・・・。

$ echo i am a perfect human | (read a; echo ${a^^})
$ echo pen-pineapple-apple-pen | (IFS=-; read -a w; echo ${w[*]^})

難しいなぁ。

Q19 Through

$ (IFS=:; while read -a w; do echo ${w[6]}; done < /etc/passwd)

難しい。ロジック自体はシンプルでbash構文を知ってるかどうか。

IFS=:
while read {a..g}
do
  case ${g} in
    */sh )
      sh=$(( ${sh} + 1 ));;
    */bash)
      bash=$(( ${bash} + 1 ));;
  esac
done < /etc/passwd
echo "bash: " ${bash}
echo "sh: " ${sh}

Q20 Catch

$ git status | grep 'modified.*B' | awk '{print $2}' | xargs git add

問題とは言えまわりくどい。--

$ git ls-files -m | grep 'B' | xargs git add

git ls-files 初めて知った。余計な処理がいらなくなる。

Q21 Catch

$ find -f . | grep -E '.css/.+|img/.+' | xargs git reset HEAD~

$ find css img -type f で事足りるのか。

Q22 Through

$ git br -a --no-merged

この先どうしたらいいのか。

$ git branch -a --no-merged |\
while read branch; \
do
  git log -1 --since=$(date -d '1 month ago' +%Y-%m-%d) $branch |\
  grep -q . || \
  git log -1 --date=short --pretty=format:"%cd | %an | $branch " $branch
done

Q23 Catch

$ git log --pretty=format:"%cd" --date=raw | awk 'BEGIN{prev=0} {if (prev != 0) { print (prev - $1)/(60 * 60); prev = $1 } else { prev = $1}}'

awk のifは変数を条件にしてやれば使わなくていい。formatも%ctを使う。

$ git log --pretty=format:"%ct" | awk 'prev{ print (prev-$0)/3600 }{ prev = $0}'

Q24 Catch

$ seq 5 1 | awk '{for(i=0;i<$0-1;i++){ printf " " } print "X"}'

Linuxだと seq 5 -1 1 にしないといけないようだ。

Q25 Catch

$ seq 1 99 | xargs -I_ ln hoge hoge_

ハードリンクとシンボリックリンクの違いとは。

Q26 Catch

$ cat kaibun
たけやぶ
やけた
$ cat not_kaibun
やぶけた
やけた
$ a=$( cat kaibun | xargs -I_ echo -n _ ); b=$( echo -n $a | ruby -ne 'print $_.reverse' ); echo -n $a $b | awk '{ if ($1==$2){print "true"}else{print "false"} }'
true
$ a=$( cat not_kaibun | xargs -I_ echo -n _ ); b=$( echo -n $a | ruby -ne 'print $_.reverse' ); echo -n $a $b | awk '{ if ($1==$2){print "true"}else{print "false"} }'
false

反転はrevでできる。
xargs _I_ echo -nxargs | tr -d ' 'でも同じ。
awk '$1==$2' 一致したときだけ出力、にすればシンプル。

paste tee <( command ) プロセス置換。

$ paste <(grep -o . kaibun) <(grep -o . kaibun | tac) | awk '$1!=$2'

模範解答はさすが。

Q27 Catch

$ seq 0 364 | xargs -I_ date -v1m -v1d -v+_d '+%m %w' | awk '$2==0' | uniq -c | awk '$1==5'

模範解答と考え方は同じ。

Q28 Through

$ curl 'https://raw.githubusercontent.com/ryuichiueda/ShellGeiData/master/sd201701/crypt' -o crypt
$ cat crypt | base64 -d | gzip -d > b; chmod +x b; ./b | sed 's/..../\\U&/g' | sed 's/.*/echo -e "&"/' | bash

難しすぎる。file コマンドしらん。

Q29 Catch

$ curl 'https://raw.githubusercontent.com/ryuichiueda/ShellGeiData/master/sd201701/alphabet_connection' -o alphabet
$ cat alphabet | xargs -n 1 | sort | xargs | ruby -nae '$F.each_with_index{|e,i| if (i==0); print e; else; if (e.ord==$F[i-1].ord+1); print "-#{e}"; else; print " #{e}" end; end}' | sed -E 's/([a-z])-[^ ]*-([a-z])/\1-\2/g'

困ったときのrubyプログラミング

Q30 Through

$ echo $BASH_COMMAND

クワイン知らないん。なんか超越した考え方だった。

Hit Rate

$ cat 30knocks.md | awk '/Catch/{c+=1} /Through/{t+=1} END{printf("Catch: %d\nThrough: %d\n%3.2f% (%d/%d)\n", c,t, (c/(c+t)*100.0), c, (c+t))}'
Catch: 19
Through: 11
63.33(19/30)