labunix's blog

labunixのラボUnix

第15回ドキッ!grepだらけのシェル芸勉強会 を解いてみた。

■第15回ドキッ!grepだらけのシェル芸勉強会 を解いてみた。

 シェル芸勉強会の自分の回答一覧(1回~第13)
 http://labunix.hateblo.jp/entry/20150316/1426433547

 シェル芸勉強会スライド一覧
 http://blog.ueda.asia/?page_id=684

 第14回東京居残りシェル芸勉強会を解いてみた。
 http://labunix.hateblo.jp/entry/20150322/1426951657

 (番外編)2015年お正月用問題 を解いてみた。
 http://labunix.hateblo.jp/entry/20150322/1427007182

■Q1.次のようにファイルを作ります。
 1という文字を含まないファイルを列挙してください(aとdですね)。

$ seq 2 5 > a;seq 1 9 > b;seq 5 11 > c;seq 3 6 > d

$ grep -L 1 [a-d] 
a
d
$ for n in {a..d};do grep 1 "$n" >/dev/null || echo $n;done
a
d

■Q2.作業ディレクトリを作り、その下に次のようにfile.1〜file.10000という
 ファイルを作ります。

以下の数字を持つファイルだけ残して後のファイルを消去してください。

    19
    10, 20, 30, …, 90
    数字の下2桁が0のファイル

$ mkdir work && cd work;seq 1 10000 | xargs -I@ touch file.@

■確認もしないで消すのは無しかな。。。

$ ls -f file* | grep "file.[1-9]\$\|file.[1-9]0\$\|file.*00\$" | \
  tr '\n' ' ' | sed s/"\(file.[0-9]* \)\{8\}"/"&\n"/g;echo
file.1 file.10 file.100 file.1000 file.10000 file.1100 file.1200 file.1300 
file.1400 file.1500 file.1600 file.1700 file.1800 file.1900 file.2 file.20 
file.200 file.2000 file.2100 file.2200 file.2300 file.2400 file.2500 file.2600 
file.2700 file.2800 file.2900 file.3 file.30 file.300 file.3000 file.3100 
file.3200 file.3300 file.3400 file.3500 file.3600 file.3700 file.3800 file.3900 
file.4 file.40 file.400 file.4000 file.4100 file.4200 file.4300 file.4400 
file.4500 file.4600 file.4700 file.4800 file.4900 file.5 file.50 file.500 
file.5000 file.5100 file.5200 file.5300 file.5400 file.5500 file.5600 file.5700 
file.5800 file.5900 file.6 file.60 file.600 file.6000 file.6100 file.6200 
file.6300 file.6400 file.6500 file.6600 file.6700 file.6800 file.6900 file.7 
file.70 file.700 file.7000 file.7100 file.7200 file.7300 file.7400 file.7500 
file.7600 file.7700 file.7800 file.7900 file.8 file.80 file.800 file.8000 
file.8100 file.8200 file.8300 file.8400 file.8500 file.8600 file.8700 file.8800 
file.8900 file.9 file.90 file.900 file.9000 file.9100 file.9200 file.9300 
file.9400 file.9500 file.9600 file.9700 file.9800 file.9900 

$ ls -f ../file* | grep "file.[1-9]\$\|file.[1-9]0\$\|file.*00\$" | \
  awk '{print "mv "$1" ."}' | sh

$ rm ../file.* && mv file.* ../ && cd ../ && rmdir tmp

■Q3.次のテキストから、「-v」、「-f」、「awk」の数をそれぞれカウントしてください。
 gawk、nawkは避けてください(awkの数としてカウントしない)。
 できる人はgrepは1個で。さらにできる人は拡張正規表現を使わないでやってみましょう。

$ cat text1
awk -v v="hoge" 'BEGIN{print v}'
echo 'BEGIN{print 1}' | gawk -f -
nawk 'BEGIN{print " BEGIN{print x}"}' | awk -v x=3 -f -

$ grep -o "\-[fv]\|^awk\| awk" text1 | tr -d ' ' | sort | uniq -c
      2 -f
      2 -v
      2 awk

■Q4./etc/の下(子、孫、・・・)のファイルのうち、シバンが「#!/bin/sh」のシェルスクリプトについて、
 中に「set -e」と記述のあるファイルとないファイルの数をそれぞれ数えてください。
 (コメント中のset -eも数えてOKです。)

$ sudo find -type f | sudo grep -l '#!/bin/sh' /etc/ -R 2>/dev/null | \
    sudo xargs grep -c 'set -e' | \
    awk -F\: '{if($2>0){ysum+=1}else{nsum+=1}};END{print "zero",nsum"\nnon zero",ysum}'
zero 304
non zero 81

■Q5.日本語やギリシャ文字のある行を除去してください。

$ cat text2 
A pen is a pen?
日本語でおk
ΩΩπ<Ω< na nandatte!!
Randy W. Bass
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
#危険シェル芸

■今回は最初の文字で区別できます。

$ LANG=C grep "^[[:print:]]*$" text2
A pen is a pen?
Randy W. Bass
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

$ awk '/^[A-z0-9]/{print}' text2
A pen is a pen?
Randy W. Bass
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

■次のようにファイルa, b, cを作ります。

$ echo 1 2 3 4 > a;echo 2 3 4 5 > b;echo 1 4 5 > c

ファイルの中の数字を足して10になるファイルを挙げてください。

$ for n in {a..c};do cat $n | tr ' ' '\n' | awk 'sum+=$1;END{print sum}' | \
  grep ^10 >/dev/null && echo $n;done
a
c

■Q7.psコマンドを打って(オプションは任意)、
 そのpsコマンドの行、親プロセスの行、親の親のプロセスの行を表示してみてください。

■親プロセスIDで再検索するだけ。

$ ps T -o ppid,pid,cmd `ps T -o ppid,pid,cmd | awk '/^ [0-9]/ {print $1}'`
 PPID   PID CMD
 4303  9240 gnome-terminal
 9240  9247 bash
 9247 10615 ps T -o ppid,pid,cmd 9240 9247

■Q8.seqとfactorの出力の後ろにgrepだけをいくつかつなげて、「素数の一つ前の数で、かつ10以上の数」を列挙してください。

■素数の一つ前で、素数ではない数が自動的に10以上なのでそのまま列挙。
 ※最初の素数は11なので。

$ seq 10 1000 | factor | grep -B 1 "[0-9]*\: [0-9]*\$" | \
  grep "[0-9]*\: [0-9]* [0-9]*" | grep -o ^[0-9]* | column
10	78	166	262	366	462	586	682	810	928
12	82	172	268	372	466	592	690	820	936
16	88	178	270	378	478	598	700	822	940
18	96	180	276	382	486	600	708	826	946
22	100	190	280	388	490	606	718	828	952
28	102	192	282	396	498	612	726	838	966
30	106	196	292	400	502	616	732	852	970
36	108	198	306	408	508	618	738	856	976
40	112	210	310	418	520	630	742	858	982
42	126	222	312	420	522	640	750	862	990
46	130	226	316	430	540	642	756	876	996
52	136	228	330	432	546	646	760	880
58	138	232	336	438	556	652	768	882
60	148	238	346	442	562	658	772	886
66	150	240	348	448	568	660	786	906
70	156	250	352	456	570	672	796	910
72	162	256	358	460	576	676	808	918