タブとスペースを含むテキストから均一な列を作成するには?

タブとスペースを含むテキストから均一な列を作成するには?

file.txt最も簡単な形式で、次の自動生成ファイルがあるとしますfile.txt

 Source                    Destination                Maximum To  Maximum From Average Total   Average To           Average From
(192.168.1.1)   (192.168.1.2)       202.89 Kbps    0 bps         645 bps 645 bps 0 bps

column私はこのコマンドをいくつかのバリエーションで試しましたが、役に立ちませんでした。この出力を次のように作成するにはどうすればよいですか?

Source         Destination     Maximum To     Maximum From     Average Total     Average To     Average From
(192.168.1.1)  (192.168.1.2)   202.89 Kbps    0 bps            645 bps           645 bps        0 bps

これを行う方法を知る必要があるようですが、空白を描いていますが、これまで期待どおりに機能している項目が見つかりませんでした。

編集する:以下の説明と回答はsed元の例と完全に一致しています。 (私は実際には説明の解決策がより簡単でパイピングを含まないので好みますtr。)つまり、両方の解決策は複数行ファイルでまったく同じパフォーマンスを発揮します。これには、file.txtさまざまな長さの数百行のIPv4アドレスが含まれます。sedこれまでのところ、両方のソリューションは元のものよりも正確な結果を次のように返しますfile.txt

ソースファイル.txt:

Source                    Destination                Maximum To  Maximum From Average Total   Average To           Average From
(10.10.10.21)     (192.168.123.122)      18.90 Kbps     0 bps         131 bps 131 bps 0 bps
(10.10.10.22)     (192.168.123.122)       10.88 Kbps     0 bps         23 bps 23 bps 0 bps
(10.10.10.23)     (192.168.123.123)       10.88 Kbps     0 bps         23 bps 23 bps 0 bps
(192.168.123.123) (192.52.168.123)       0 bps          22.84 Kbps    1.17 Kbps 0 bps     1.17 Kbps
(192.168.123.124)  (192.52.168.123)       0 bps          10.87 Kbps    19 bps 0 bps  19 bps

更新されたfile.txt(これまで提案されたソリューションを使用した後):

Source                              Destination        Maximum To  Maximum From  Average Total  Average To  Average From
(10.10.10.21)                       (192.168.123.122)  18.90 Kbps  0 bps         131 bps        131 bps     0 bps
(10.10.10.22)                       (192.168.123.122)  10.88 Kbps  0 bps         23 bps         23 bps      0 bps
(10.10.10.23)                       (192.168.123.123)  10.88 Kbps  0 bps         23 bps         23 bps      0 bps
(192.168.123.123) (192.52.168.123)  0 bps              22.84 Kbps  1.17 Kbps     0 bps          1.17 Kbps
(192.168.123.124)                   (192.52.168.123)   0 bps       10.87 Kbps    19 bps         0 bps       19 bps

このオフセット警告を解決するための更新されたソリューションはありますか?

答え1

スクリプトはOPのサンプルデータに基づいています。

sed '
    s/\s\s\+/:/g
    s/\([a-z)]\)\s\([(0-9A]\)/\1:\2/g
    ' file.txt | 
column -s: -t
  • 見つけやすい区切り文字を変更して始めます(\s手順2以降)。:
  • 2番目のステップでは、残りの可能な区切り文字を探します。
    • 小文字と数字の間
    • 後ろに)
    • 今後A
  • 列区切り文字を使用した文字列の書式設定:

答え2

次のPerlスクリプトは、最初の2つのフィールドにそれぞれ1つの「単語」があり、残りのフィールドには2つの「単語」があるという知識に基づいて、入力をタブ区切りフィールドに変換します。その後、出力は次にパイプされます。column -s $'\t' -t

これはやや不器用で無差別的なアプローチですが、うまくいきます。

#! /usr/bin/perl 

use strict;

while(<>) {
    my (@F, @fields, $i);

    @F=split;
    $fields[0] = $F[0] ;
    $fields[1] = $F[1] ;
    for $i (0..4) {
      $fields[$i + 2] = $F[$i*2 + 2] . ' ' . $F[$i*2 + 3];
    }

    print join("\t",@fields),"\n";
}

使用方法は次のとおりです。

$ ./bandwidth.pl bandwidth.txt | column -s $'\t' -t 
Source             Destination        Maximum To  Maximum From  Average Total  Average To  Average From
(10.10.10.21)      (192.168.123.122)  18.90 Kbps  0 bps         131 bps        131 bps     0 bps
(10.10.10.22)      (192.168.123.122)  10.88 Kbps  0 bps         23 bps         23 bps      0 bps
(10.10.10.23)      (192.168.123.123)  10.88 Kbps  0 bps         23 bps         23 bps      0 bps
(192.168.123.123)  (192.52.168.123)   0 bps       22.84 Kbps    1.17 Kbps      0 bps       1.17 Kbps
(192.168.123.124)  (192.52.168.123)   0 bps       10.87 Kbps    19 bps         0 bps       19 bps

これは、区切りフィールドに区切り文字(スペースなど)を使用することが決して良い考えではない理由を示す良い例です。これは必要以上に状況をより困難にするだけであり、ファイルの内容と構造に関する事前の知識がなければ、区切り文字とフィールドの内容を区別するための信頼できる方法はありません。

答え3

修正する:次の例では、名前付きソース全体のコピーを使用してくださいfull_original.txt

$ sed 's/\((\)/ \1/g;s/\(Average\)/ \1/g;s/ \([0-9]\)/  \1/g;s/\(\S\) \(\S\)/\1_\2/g' full_original.txt | column -t | tr _ ' '
Source             Destination        Maximum To  Maximum From  Average Total  Average To  Average From
(10.10.10.21)      (192.168.123.122)  18.90 Kbps  0 bps         131 bps        131 bps     0 bps
(10.10.10.22)      (192.168.123.122)  10.88 Kbps  0 bps         23 bps         23 bps      0 bps
(10.10.10.23)      (192.168.123.123)  10.88 Kbps  0 bps         23 bps         23 bps      0 bps
(192.168.123.123)  (192.52.168.123)   0 bps       22.84 Kbps    1.17 Kbps      0 bps       1.17 Kbps
(192.168.123.124)  (192.52.168.123)   0 bps       10.87 Kbps    19 bps         0 bps       19 bps

説明する

このソリューションの多くは、いくつかの個別の問題があり、それらを個別に解決する「分割と征服」アプローチに従います。最後に、仕上げタッチのための魔法命令でcolumn組み立てられますtr

  • Greedy / Globalの場合はデフォルトのパターンであるため、最初の一致だけs/searchstring/replacestring/g'gなくすべての一致にも適用されます。
  • グループ化を使用しているため、検索セクションで「最初のグループの場合」、「2番目のグループの場合」などで再\(somegroup\)印刷できます。\1\2
  • セミコロンを使用すると、パイプよりも効率的に;複数の検索および置換コマンドを単一のインスタンスに配置できるsedため、複数のsedを実行できますsed command | sed command | sed command ....
  • s/\((\)/ \1/g...123) (19...OPが検出したオフセットの問題を避けるために、括弧で囲まれた2つのIP値を2つ以上のスペースで押し出す操作を処理します。左角かっこを一致させ、(前にスペースを付けてこれを行いますspace(
  • s/\(Average\)/ \1/g特に別個の部品がないため、Maximum From Average Total後で見つけて交換するのが難しくなる問題を解決するために、最初は各項目の前に追加のスペースを追加しました。Average
  • s/ \([0-9]\)/ \1/g645 bps 645 bps 0 bps発生前にスペースを追加してspace+number元のテキストのフィールド値を分離すると、space+space+number後続のsedコマンドがそれを区別するのに役立ちます。
  • 最後のsedコマンドs/\(\S\) \(\S\)/\1_\2/gは回避策で、non-space+space+non-spaceスペースが下線になるようにグループ化して検索して変更します。これは Maximum To後でcolumn使用するコマンドのために一緒に保持されます。Maximum_To
  • | column -tこれを列コマンドにパイプすると、デフォルトでは次のようにman column表示されます。By default, the column command will merge multiple adjacent delimiters into a single delimiter when using the -t optionしたがって、テキスト間の可変スペースを単一の区切り文字として扱います。
  • 列は、テキストの並べ替えのために書式の再指定も実行します。
  • | tr _ ' '最後に、空白をアンダースコア()に変換コマンドを使用して解決策を元に戻し、すべてを空白に戻します。_tr_' '

これにより、目的の出力を得ることができます。

関連情報