Bashスクリプトを使用したファイルの並べ替え

Bashスクリプトを使用したファイルの並べ替え

この記事を読んでくれてありがとう。私はbashに初めて触れたので、次のアドバイスが必要です。

2つの列を含むファイルを読み取るbashスクリプトを作成したいと思います。

f  2
g  1
s  4
d  5
f  2
g  5
d  9
g  10
h  1
s  5
d  29

私のスクリプトは実際に最初の列(アルファベット)に基づいてファイルをソートし、という名前のファイルを生成し、数字で同じことを行い、alpha_sorted.txt名前を付けたいと思いますnumbers_sorted.txt

私はこの分野に慣れていないので、可能であればあなたの助けを求めたいと思い、文書やリンクを提供したり、コードの助けを得たいと思います。

このスクリプトは初級レベルの使用のためであるため、アプローチを複雑にすることはお勧めできません。

修正する

john1024の答えを使用して、次の問題が発生しました。

Hasan@HasanChr /cygdrive/c/users/Hasan/Desktop/Bash
$ chmod +x script.sh

Hasan@HasanChr /cygdrive/c/users/Hasan/Desktop/Bash
$ ./script.sh
cat: alpha_sorted.txt: No such file or directory

スクリーンショットscript.sh

ここに画像の説明を入力してください。

答え1

この記事がに投稿されて以来Unix.stackexchange.com、一般的なUNIXツールにアクセスできるとします。

最初の列はアルファベット順に並べられます。

$ sort file.txt >alpha_sorted.txt
$ cat alpha_sorted.txt
d  29
d  5
d  9
f  2
f  2
g  1
g  10
g  5
h  1
s  4
s  5

数値ソート:

$ sort -nk2,2 file.txt >numbers_sorted.txt
$ cat numbers_sorted.txt
g  1
h  1
f  2
f  2
s  4
d  5
g  5
s  5
d  9
g  10
d  29

-n数値ソートを指定します。 -k2,2ソートする2番目の列を指定します。

詳細についてはを参照してくださいman sort

メモ帳を使用してUnixスクリプトを編集するときに発生する問題

DOS行の終わりにスクリプトを作成しました。

$ cat dos.sh
sort file.txt >alpha_sorted.txt
cat alpha_sorted.txt 

見えませんが、コマンドの最後にスペースを追加しましたcat。このファイルを使用すると、表示されるエラーを再現できます。

$ chmod +x dos.sh
$ dos.sh
cat: alpha_sorted.txt: No such file or directory
: No such file or directory

dos2unixまたはなどのユーティリティを使用してこの問題を解決できますtr。使用tr:

$ tr -d '\r' <dos.sh >fixed.sh
$ chmod +x fixed.sh

これで、次のコマンドを正常に実行できます。

$ fixed.sh
d  29
d  5
d  9
f  2
f  2
g  1
g  10
g  5
h  1
s  4
s  5

答え2

より良いソート方法があります。bashでのみ行う代わりに。これはあなたの質問に対する良い答えではありません。単純ではなく(bashのいくつかの一般的な機能を使用しているため)、事前に構築されたタスクを実行するために使用されても、「Unix方式」ではタスクを実行しません。何かをし、それをうまくやってください(ソートなど)。

アカウントのデフォルトシェルがコマンドの実行とI / Oリダイレクト用に構築されていることを明確にするために、この回答を作成することにしました。殻があるという理由だけでBashなどのさまざまな機能特定の作業に最適なツールという意味ではありません。代わりに、awkまたはperl(またはjqまたはsort ...)を使用することを提案する答えをここでよく見ることができます。シェルスクリプトでハッキング

そういえば、bashできるソート - 組み込みではありません。もう一度申し上げますが、これはまだ良い考えではありません。しかし、あなたはできます。以下は、bashに実装されている4つの機能です。タイプ2つのフィールドのそれぞれには2つの方法があります。

これらの機能は以下を使用します。

挿入ソートが効率的ではありません(O(n) 2)、しかし11行の例のような小さなデータセットは間違いなく合理的です。サンプルデータの場合、4つの関数が1秒未満で実行されたがランダムに生成された1,000行の入力ファイルの場合、「単一配列」のソートには約15秒かかり、「内部」バージョンは約60秒かかりました。再処理。これを比較する標準ソートユーティリティ1000分の1秒で、すべての列の1,000行のファイルを並べ替えます。

これら2つの「in-place」関数は、配列(そして値を繰り返し交換するためのいくつかの1回限りの変数)のみを生成していくつかのバイトを節約しようとし、きちんとしたbash関数を使用してファイルを変換します。配列として。 「キーイング」機能は風に注意を払います二つソートに必要なキーの配列と実際の値の配列を分離します。

function sort_inplace_f1 {
  local array
  mapfile -t array < "$1"
  local i j tmp
  for ((i=0; i <= ${#array[@]} - 2; i++))
  do
    for ((j=i + 1; j <= ${#array[@]} - 1; j++))
    do
      local ivalue jvalue
      [[ ${array[i]} =~ ([^[:space:]]+)[[:space:]]+(.*) ]]
      ivalue="${BASH_REMATCH[1]}"
      [[ ${array[j]} =~ ([^[:space:]]+)[[:space:]]+(.*) ]]
      jvalue=${BASH_REMATCH[1]}
      if [[ $ivalue > $jvalue ]]
      then
        tmp=${array[i]}
        array[i]=${array[j]}
        array[j]=$tmp
      fi
    done
  done
  printf "%s\n" "${array[@]}"
}

function sort_inplace_f2 {
  local array
  mapfile -t array < "$1"
  local i j tmp
  for ((i=0; i <= ${#array[@]} - 2; i++))
  do
    for ((j=i + 1; j <= ${#array[@]} - 1; j++))
    do
      local ivalue jvalue
      [[ ${array[i]} =~ ([^[:space:]]+)[[:space:]]+(.*) ]]
      ivalue="${BASH_REMATCH[2]}"
      [[ ${array[j]} =~ ([^[:space:]]+)[[:space:]]+(.*) ]]
      jvalue=${BASH_REMATCH[2]}
      if [[ $ivalue > $jvalue ]]
      then
        tmp=${array[i]}
        array[i]=${array[j]}
        array[j]=$tmp
      fi
    done
  done
  printf "%s\n" "${array[@]}"
}

function sort_keyed_f1 {
  local c1 c2 keys values
  while IFS=' ' read -r c1 c2
  do
    keys+=("$c1")
    values+=("$c1 $c2")
  done < "$1"

  local i j tmpk tmpv
  for ((i=0; i <= ${#keys[@]} - 2; i++))
  do
    for ((j=i + 1; j <= ${#keys[@]} - 1; j++))
    do
      if [[ ${keys[i]} > ${keys[j]} ]]
      then
        # swap keys
        tmpk=${keys[i]}
        keys[i]=${keys[j]}
        keys[j]=$tmpk
        # swap values
        tmpv=${values[i]}
        values[i]=${values[j]}
        values[j]=$tmpv
      fi
    done
  done
  printf "%s\n" "${values[@]}"
}

function sort_keyed_f2 {
  local c1 c2 keys values
  while IFS=' ' read -r c1 c2
  do
    keys+=("$c2")
    values+=("$c1 $c2")
  done < "$1"

  local i j tmpk tmpv
  for ((i=0; i <= ${#keys[@]} - 2; i++))
  do
    for ((j=i + 1; j <= ${#keys[@]} - 1; j++))
    do
      if [[ ${keys[i]} -gt ${keys[j]} ]]
      then
        # swap keys
        tmpk=${keys[i]}
        keys[i]=${keys[j]}
        keys[j]=$tmpk
        # swap values
        tmpv=${values[i]}
        values[i]=${values[j]}
        values[j]=$tmpv
      fi
    done
  done
  printf "%s\n" "${values[@]}"
}

これらすべてがあった後でも、まだシェルの重要な「機能」の1つ、つまり出力をファイルにリダイレクトする必要があります。

sort_keyed_f1 input-file > alpha_sorted.txt
sort_keyed_f2 input-file > numbers_sorted.txt

関連情報