第22回シェル芸勉強会に参加してきました(復習) #2 後半分

第22回シェル芸勉強会の復習(後半)。

Q5.

ファイルの中から、足して10になる並びを抽出するという問題。
これについては、後から調べてみたけどもawkでゴリ押しするしかなさそうだ。
以下、模範回答から。

cat Q5 | awk '{for(len=1;len<=NF;len++)for(shift=1;shift<=NF-len+1;shift++){for(i=shift;i<shift+len;i++){printf $i" "};print ""}}' | awk '{a=0;for(i=1;i<=NF;i++)a+=$i;print $0,a}'
[root@test-node vol.22]# cat Q5 | \
 awk '
 {
 for(len=1;len<=NF;len++)
 for(shift=1;shift<=NF-len+1;shift++){
     for(i=shift;i<shift+len;i++){printf $i" "};print ""
     }
 }'
1
3
4
4
…
4 4 2 3 5 6 7 9 1 4
1 3 4 4 2 3 5 6 7 9 1
3 4 4 2 3 5 6 7 9 1 4
1 3 4 4 2 3 5 6 7 9 1 4
[root@test-node vol.22]#
[root@test-node vol.22]# # 抽出した全ての組み合わせの合計を求める
[root@test-node vol.22]# cat Q5 | \
 awk '
 {
 for(len=1;len<=NF;len++)
 for(shift=1;shift<=NF-len+1;shift++){
     for(i=shift;i<shift+len;i++){printf $i" "};print ""
     }
 }' | \
 awk '{a=0;for(i=1;i<=NF;i++)a+=$i;print $0,a}'
1  1
3  3
4  4
4  4
2  2
3  3
5  5
6  6
7  7
9  9
1  1
4  4
1 3  4
3 4  7
…
4 4 2 3 5 6 7 9 1  41
4 2 3 5 6 7 9 1 4  41
1 3 4 4 2 3 5 6 7 9  44
3 4 4 2 3 5 6 7 9 1  44
4 4 2 3 5 6 7 9 1 4  45
1 3 4 4 2 3 5 6 7 9 1  45
3 4 4 2 3 5 6 7 9 1 4  48
1 3 4 4 2 3 5 6 7 9 1 4  49
[root@test-node vol.22]#
[root@test-node vol.22]#
[root@test-node vol.22]# # 「10」という値のある列を持つ行を出力する
[root@test-node vol.22]# cat Q5 | \
 awk '
 {
 for(len=1;len<=NF;len++)
 for(shift=1;shift<=NF-len+1;shift++){
     for(i=shift;i<shift+len;i++){printf $i" "};print ""
     }
 }' | \
 awk '{a=0;for(i=1;i<=NF;i++)a+=$i;print $0,a}' | \
 awk '$NF==10'
9 1  10
4 4 2  10
2 3 5  10

Q6.

特定のファイル内で定義されている値を代入(置換)するという問題。
値が定義されているファイルの内容を、sed -fで読み込める形にしてやることで対処できる。

sed -f <(awk '{print "s/"$1"/"$2"/g"}' Q6_2) Q6_1

[root@test-node vol.22]# cat Q6_1
所謂いわゆる「Z」というものにだって、
もっと何か表情なり印象なりがあるものだろうに、
YのからだにXでもくっつけたなら、
こんな感じのものになるであろうか、
とにかく、どこという事なく、見る者をして、
ぞっとさせ、いやな気持にさせるのだ。
私はこれまで、こんな不思議な男の顔を見た事が、
やはり、いちども無かった。
[root@test-node vol.22]# cat Q6_2
X 駄馬の首
Y 人間
Z 死相
[root@test-node vol.22]# awk '{print "s/"$1"/"$2"/g"}' Q6_2
s/X/駄馬の首/g
s/Y/人間/g
s/Z/死相/g
[root@test-node vol.22]# sed -f <(awk '{print "s/"$1"/"$2"/g"}' Q6_2) Q6_1
所謂いわゆる「死相」というものにだって、
もっと何か表情なり印象なりがあるものだろうに、
人間のからだに駄馬の首でもくっつけたなら、
こんな感じのものになるであろうか、
とにかく、どこという事なく、見る者をして、
ぞっとさせ、いやな気持にさせるのだ。
私はこれまで、こんな不思議な男の顔を見た事が、
やはり、いちども無かった。

Q7.

現在開いているターミナルのみを閉じるという問題。
解いてる際、無駄に長い回答を出してしまった。

ps -ef | grep $(echo $SSH_TTY | sed 's/\/dev\///') | awk '{print $2}' | xargs kill -9

が、実際にはexecコマンドで適当なコマンドを実行するか、$$(ターミナルのプロセス)をそのままkillしてやればいいようだ。

exec echo
kill -9 $$

Q8.

C++のソースコードに、必要なコードを追記するという問題。
ebanさんがすごい回答を出してたので、それを参照。

…... Σ(゚ ω゚ ) !
さっぱりわからない…分解してみよう。

sed '/void/!d;s/$/;/' Q8.cc | sed '/name/r/dev/stdin' Q8.cc
[root@test-node vol.22]# # ※前提知識として、sedでは'条件1;条件2'って感じで書けるのを踏まえる事
[root@test-node vol.22]# # 「void」を含まない行を除外
[root@test-node vol.22]# #    /void/!d
[root@test-node vol.22]# #  行の末尾($)を「;」に置換
[root@test-node vol.22]# #    s/$/;/
[root@test-node vol.22]# sed '/void/!d;s/$/;/' Q8.cc
void aho(void);
string nazo(void);
[root@test-node vol.22]#
[root@test-node vol.22]# # sedで記述する際、「追記場所r ファイル名」を用いる事で指定したファイルから読み込んだ内容を追記するこ とが出来る。
[root@test-node vol.22]# # 今回の指定方法「r/dev/stdin」では、標準出力から読み込む事が出来る。
[root@test-node vol.22]# # また、「/name/r」で「name」のある行の後ろに追記される。
[root@test-node vol.22]# sed '/void/!d;s/$/;/' Q8.cc | sed '/name/r/dev/stdin' Q8.cc
#include 
#include 
using namespace std;
void aho(void);
string nazo(void);

void aho(void)
{
        cout << nazo() << endl;
}

string nazo(void)
{
        return "謎";
}

int main(int argc, char const* argv[])
{
        aho();
        return 0;
}

これをコンパイルしてみよう。

[root@test-node vol.22]# sed '/void/!d;s/$/;/' Q8.cc | sed '/name/r/dev/stdin' Q8.cc > Q8_.cc
[root@test-node vol.22]# g++ Q8_.cc
[root@test-node vol.22]# ./a.out
謎

なお、勉強会中に話題になったのだが、g++では「-xc++」を付与することで標準出力からコンパイルさせることも出来るようだ。

[root@test-node vol.22]# ls -la a.out
ls: a.out にアクセスできません: そのようなファイルやディレクトリはありません
[root@test-node vol.22]# sed '/void/!d;s/$/;/' Q8.cc | sed '/name/r/dev/stdin' Q8.cc | g++ -xc++ - ; ./a.out
謎

今回も勉強になった(あんま解けなかったけど…)。
ただまぁ、もうちょい回答できるようになりたいなぁ…。