ブレース展開を使って特定のコマンドへパイプ越しに繰り返し処理をさせるワンライナーを、パイプを増やしやすく書く

ハッシュのストレッチングみたいなことをbashでできたら面白いかなと思って調べてたのだけど、特定のコマンドにパイプでn回値を渡す、というような処理はちょっと書くのが難しいようで、以下のようにforとか使ってやる必要があるみたいだ。

# 'Hello World!Yeah!'を3回sha256でストレッチングするという処理をしてる
echo 'Hello World!Yeah!' | (read v; for i in {1..3};do v=$(echo $v | (sha256sum|awk '{print $1}'));done;echo $v;)
echo 'Hello World!Yeah!' | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}')
[root@BS-PUB-CENT7-01 ~]# # 'Hello World!Yeah!'を3回sha256でストレッチングするという処理をしてる
[root@BS-PUB-CENT7-01 ~]# echo 'Hello World!Yeah!' | (read v; for i in {1..3};do v=$(echo $v | (sha256sum|awk '{print $1}'));done;echo $v;)
13ee5ecfc8a123d816aae799d5233281622ef66d88a3f4e3a8a86655452218b4
[root@BS-PUB-CENT7-01 ~]#
[root@BS-PUB-CENT7-01 ~]# # 同じ処理をパイプで
[root@BS-PUB-CENT7-01 ~]# echo 'Hello World!Yeah!' | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}')
13ee5ecfc8a123d816aae799d5233281622ef66d88a3f4e3a8a86655452218b4

 

一応、回数も数字で指定できるし、悪くはないけどforということでシングルタスクというのもあるからか、どことなくレスポンスが遅い。

[root@BS-PUB-CENT7-01 ~]# time echo 'Hello World!Yeah!' | (read v; for i in {1..3};do v=$(echo $v | (sha256sum|awk '{print $1}'));done;echo $v;)
13ee5ecfc8a123d816aae799d5233281622ef66d88a3f4e3a8a86655452218b4
real    0m0.544s
user    0m0.003s
sys     0m0.014s
[root@BS-PUB-CENT7-01 ~]# time echo 'Hello World!Yeah!' | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}')
13ee5ecfc8a123d816aae799d5233281622ef66d88a3f4e3a8a86655452218b4
real    0m0.114s
user    0m0.003s
sys     0m0.009s
Sponsored Links

これではちょっと面白く無いよねということで、数字での回数指定はできないけれどブレース展開を使ってパイプをつなげ続けるのと同等の処理をさせてみた。
以下、実行例。

eval $(set echo\ 'Hello World!Yeah!' '(sha256sum|awk "{print \$1}")'{,,};IFS=\|;echo "$*")
[root@BS-PUB-CENT7-01 ~]# echo $(set echo\ 'Hello World!Yeah!' '(sha256sum|awk "{print \$1}")'{,,};IFS=\|;echo "$*")
echo Hello World!Yeah!|(sha256sum|awk "{print \$1}")|(sha256sum|awk "{print \$1}")|(sha256sum|awk "{print \$1}")
[root@BS-PUB-CENT7-01 ~]# eval $(set echo\ 'Hello World!Yeah!' '(sha256sum|awk "{print \$1}")'{,,};IFS=\|;echo "$*")
13ee5ecfc8a123d816aae799d5233281622ef66d88a3f4e3a8a86655452218b4
[root@BS-PUB-CENT7-01 ~]# time eval $(set echo\ 'Hello World!Yeah!' '(sha256sum|awk "{print \$1}")'{,,};IFS=\|;echo "$*")
13ee5ecfc8a123d816aae799d5233281622ef66d88a3f4e3a8a86655452218b4
real    0m0.174s
user    0m0.004s
sys     0m0.010s

 

ちょっとわかりにくい書き方になってしまうのだが、まぁ回数増やすのにはカンマ(,)足すだけだし、悪くは無さそう。
ちなみに、試しにパイプを通してコマンドを実行する回数を10回くらいにした場合のパフォーマンスはこんな感じ。

[root@BS-PUB-CENT7-01 ~]# time echo 'Hello World!Yeah!' | (read v; for i in {1..10};do v=$(echo $v | (sha256sum|awk '{print $1}'));done;echo $v;)
6b88b3fa44e36e030c175b5d53139079e7f660712c4ae005174dc2fcabe1a4f5
real    0m1.689s
user    0m0.009s
sys     0m0.036s
[root@BS-PUB-CENT7-01 ~]# time echo 'Hello World!Yeah!' | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}') | (sha256sum|awk '{print $1}')
6b88b3fa44e36e030c175b5d53139079e7f660712c4ae005174dc2fcabe1a4f5
real    0m0.158s
user    0m0.008s
sys     0m0.034s
[root@BS-PUB-CENT7-01 ~]# time eval $(set echo\ 'Hello World!Yeah!' '(sha256sum|awk "{print \$1}")'{,,,,,,,,,};IFS=\|;echo "$*")
6b88b3fa44e36e030c175b5d53139079e7f660712c4ae005174dc2fcabe1a4f5
real    0m0.206s
user    0m0.008s
sys     0m0.033s

 

単純にパイプつなげただけの処理には及ばないものの、単純にforを使った処理に比べたらかなり早いようだ。

 


Written by blacknon

インフラ系のSE。一時期はプログラマ。 仮想化とオープンソースに興味あり。一日中寝てたい今日このごろ。 スペインとかで働きたいなぁ…(シエスタがあるので)

Leave a Comment

メールアドレスが公開されることはありません。

*