改行で区切られた文字列を含むテキストファイルがあります。私の問題は、各行を次のように処理することです。スペースを区切り文字として使用して、トークンの順序を混在させます。
たとえば、
入力する:
A B C
出力:
C A B
もちろん、コマンド/スクリプトを繰り返し実行する場合は、別の順序を指定する必要があります。
私の現在のソリューション(1行のテキスト):
$ cat <file> | tr " " "\n" | shuf | tr "\n" " "
複数行のテキストファイルを処理するための良い(より良い)コマンドラインの組み合わせはありますか?
答え1
POSIXlyでは、これを比較的効率的に実行できます(確かに、awk
すべての入力行に対して1つ以上のGNUユーティリティを実行するよりも効率的です)。shuf
awk '
BEGIN {srand()}
{
for (i = 1; i <= NF; i++) {
r = int(rand() * NF) + 1
x = $r; $r = $i; $i = x
}
print
}' < your-file
(ほとんどのawk
実装では、同じコマンドを同じ秒以内に2回実行すると同じ結果が得られます。使用されるデフォルトのランダムシードはsrand()
通常、秒単位の現在のエポック時間に基づいているためです)。
答え2
元のコマンドを次のように単純化できます。
shuf -e A B C | tr "\n" " " && echo ""
または
shuffled=( $(shuf -e A B C) ) ; echo ${shuffled[*]}
私の考えでは、これは基本的なテストよりも面倒で、より速いと思います。
~/test
埋め込みファイルがある場合
A B C
D E F
以下を使用して、各ラインをスクランブルしてエコーすることができます。
while IFS= read -r line; do shuffled=( $(shuf -e $line) ) ; echo ${shuffled[*]} ; done < ~/test
またはスクリプト形式で:
#!/bin/bash
while IFS= read -r line
do shuffled=( $(shuf -e $line) )
echo ${shuffled[*]}
done < ~/test
スクリプトに引数を渡す~/test
場所を変更できます。$1
結果:
B C A
G E F
動作原理:
shuf -e
スペースと改行に分割されます。しかし、これはABCを3つの引数として扱うからです。
したがって、
shuf -e A B C
ABとCの順序は壊れますが、shuf -e "A B C"
ABとCの順序は壊れません。
これを使用して各行を配列に読み込んでから、もう一度印刷できますecho
。
while IFS= read -r line;
$line
各行はこのループに渡されると読み込まれます<
。
do shuffled=( $(shuf -e $line) )
$shuffled
リテラル拡張により、shuf -e $line
変数の各行に配列が作成されますshuf -e A B C
。
echo ${shuffled[*]}
デフォルトでは、各要素の間にスペースを入れて印刷する配列をエコーします。
< ~/test
~/test
ループに行を入力します。
答え3
与えられた
$ cat file
A B C
D E F
G H I J
shuffle
次に、PerlのList :: Utilモジュールを使用してください。
$ perl -MList::Util=shuffle -alpe '$_ = join " ", shuffle @F' file
C B A
E D F
I J G H
bashを使用read -a
してshuf
(ただし、1行に3つのユーティリティを実行し、そのうちの2つは組み込まれていないため、非常に非効率的です):
$ while read -ra arr; do shuf -e -- "${arr[@]}" | paste -sd ' ' -; done < file
A C B
F E D
J I G H
答え4
パラメータを1行で渡すには:
shuf -e one two three four
それはあなたが必要とするすべてです。
shuf -e $(cat <file>) | tr "\n" " "
例に示すように、1行しかないファイルの場合。
複数行の場合:
while read line; do shuf -e $line | tr "\n" " " && echo \n; done < <file>