ハッシュのストレッチングみたいなことを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

<span style="color: #ff0000;">real    0m0.544s</span>
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

<span style="color: #ff0000;">real    0m0.114s</span>
user    0m0.003s
sys     0m0.009s

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

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

<span style="color: #ff0000;">real    0m1.689s</span>
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

<span style="color: #ff0000;">real    0m0.158s</span>
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

<span style="color: #ff0000;">real    0m0.206s</span>
user    0m0.008s
sys     0m0.033s

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