文字列の単語を混ぜる

文字列の単語を混ぜる

改行で区切られた文字列を含むテキストファイルがあります。私の問題は、各行を次のように処理することです。スペースを区切り文字として使用して、トークンの順序を混在させます。

たとえば、

入力する: 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>

関連情報