twitter で一瞬話題になってたのを見かけたのでちょっとだけ使ってみた。
が perl だったのでげんなり。 xargs -P と比べれば早くはないけど、 pcntl_fork() なんかに比べればだいぶ早い。
% time seq 1000 | xargs -P4 -I{} echo {} >/dev/null
seq 1000 0.00s user 0.00s system 0% cpu 0.003 total
xargs -P4 -I{} echo {} > /dev/null 0.12s user 0.39s system 268% cpu 0.191 total
% time seq 1000 | parallel -P4 -I{} echo {} >/dev/null
seq 1000 0.00s user 0.00s system 0% cpu 0.003 total
parallel -P4 -I{} echo {} > /dev/null 1.24s user 1.60s system 150% cpu 1.882 total
試行錯誤した限りだと、 {} がないと arg に必ず入っちゃうのかな?
% seq 3 | xargs -I{} sh -c 'set -x; ps h -p $$ -o pid,pgid'
+ ps h -p 4056 -o pid,pgid
4056 4054
+ ps h -p 4058 -o pid,pgid
4058 4054
+ ps h -p 4060 -o pid,pgid
4060 4054
% seq 3 | parallel -I{} 'set -x; ps h -p $$ -o pid,pgid'
+ ps h -p 4193 -o pid,pgid 1
1 1
4193 4153
+ ps h -p 4194 -o pid,pgid 2
2 0
4194 4153
+ ps h -p 4196 -o pid,pgid 3
3 0
4196 4153
ファイル名を便利に扱うための置換マーカみたいなのが最初から入ってる。 {} = aho/baka.dat だとして
- {.} = aho/baka
- {/} = baka.dat
- {/.} = baka
となる。 paralles ssh 的に使うと便利、みたいな例が幾つか上がってて、たしかに DNS 的ホスト名もファイル名も "." で区切るよな、と思った。
なんでちょっといじった。いや、ほら、だいたい 3 つ削ればホスト名になるじゃん。
-- ./opt/src/parallel/parallel-20110322/src/parallel 2011-03-22 09:00:52.000000000 +0900
+++ /home/ichii386/opt/bin/parallel 2011-04-25 21:06:51.000000000 +0900
@@ -391,8 +391,12 @@
$Global::quoting = 0;
$Global::replace{'{}'} = '{}';
$Global::replace{'{.}'} = '{.}';
+ $Global::replace{'{..}'} = '{..}';
+ $Global::replace{'{...}'} = '{...}';
$Global::replace{'{/}'} = '{/}';
$Global::replace{'{/.}'} = '{/.}';
+ $Global::replace{'{/..}'} = '{/..}';
+ $Global::replace{'{/...}'} = '{/...}';
$/="\n";
$Global::ignore_empty = 0;
$Global::interactive = 0;
@@ -3092,7 +3096,11 @@
'{}' => 0, # Total length of all {} replaced with all args
'{/}' => 0, # Total length of all {/} replaced with all args
'{.}' => 0, # Total length of all {.} replaced with all args
+ '{..}' => 0, # Total length of all {..} replaced with all args
+ '{...}' => 0, # Total length of all {...} replaced with all args
'{/.}' => 0, # Total length of all {/.} replaced with all args
+ '{/..}' => 0, # Total length of all {/..} replaced with all args
+ '{/...}' => 0, # Total length of all {/...} replaced with all args
'no_args' => undef, # Length of command with all replacement args removed
'context' => undef, # Length of context of an additional arg
};
@@ -3903,11 +3911,27 @@
# skip
} elsif($replacement_string eq "{.}") {
$s =~ s:\.[^/\.]*$::; # Remove .ext from argument
+ } elsif($replacement_string eq "{..}") {
+ $s =~ s:\.[^/\.]*$::; # Remove .ext from argument
+ $s =~ s:\.[^/\.]*$::; # Remove .ext from argument
+ } elsif($replacement_string eq "{...}") {
+ $s =~ s:\.[^/\.]*$::; # Remove .ext from argument
+ $s =~ s:\.[^/\.]*$::; # Remove .ext from argument
+ $s =~ s:\.[^/\.]*$::; # Remove .ext from argument
} elsif($replacement_string eq "{/}") {
$s =~ s:^.*/([^/]+)/?$:$1:; # Remove dir from argument. If ending in /, remove final /
} elsif($replacement_string eq "{/.}") {
$s =~ s:^.*/([^/]+)/?$:$1:; # Remove dir from argument. If ending in /, remove final /
$s =~ s:\.[^/\.]*$::; # Remove .ext from argument
+ } elsif($replacement_string eq "{/..}") {
+ $s =~ s:^.*/([^/]+)/?$:$1:; # Remove dir from argument. If ending in /, remove final /
+ $s =~ s:\.[^/\.]*$::; # Remove .ext from argument
+ $s =~ s:\.[^/\.]*$::; # Remove .ext from argument
+ } elsif($replacement_string eq "{/...}") {
+ $s =~ s:^.*/([^/]+)/?$:$1:; # Remove dir from argument. If ending in /, remove final /
+ $s =~ s:\.[^/\.]*$::; # Remove .ext from argument
+ $s =~ s:\.[^/\.]*$::; # Remove .ext from argument
+ $s =~ s:\.[^/\.]*$::; # Remove .ext from argument
}
if($Global::JobQueue->quote_args()) {
$s = ::shell_quote_scalar($s);
ところで、この手のやつで先頭にホスト名入れたい時ってどうします?
% get_host_list | parallel -I{} 'ssh {} "ps -unko -opid,pgrp,nice,etime,stime,stat,args | sort -k4 -nr | head -n3" | sed "s/^/{...}: /"'
とかかな。でも sed って quote とか escape とかめんどいし、パッと見なにしてるかわかんなくてやなんですよね。
あとは 'while read line; do echo "{}: $line"; done' とか? いやー。なんとか yes と paste 組み合わせてなんかできないかと試行錯誤して、諦めました。並列 ssh 専用だったら他に解は沢山あるし。
感想
よくこんなの GNU に入ったね、って思った。なんというか、流儀とかいろいろ。