「列」の出力がANSIカラー入力と一致しないのはなぜですか?

「列」の出力がANSIカラー入力と一致しないのはなぜですか?

一部のデータを取得するためにコマンドラインを使用しています(カール)、関連フィールド抽出(アッ)形式を指定し()。

見苦しいですがうまくいきます(しかし、すべてのスクリプトは「長くて醜い」1行)しかし、特定の色をリストしようとすると間違っています。

これは単純な(単純化された)バージョンです。働く:

curl "http://webservices.rm.ingv.it/fdsnws/event/1/query?lat=42.35&lon=13.4&maxradius=5.0&starttime=2016-01-01T00:00:00&endtime=2016-12-31T23:59:59&minmag=5&format=text&orderby=time-asc" 2>/dev/null  \
 | awk 'BEGIN { FS= "|"; OFS= "|" }  {print  $1, $2, $5, $10, $11, $13}' \
 | column -t -s '|'

今、いくつかのフィールドに下線を引いていくつかを追加したいと思います。ANSIエスケープコードまったく:

curl "http://webservices.rm.ingv.it/fdsnws/event/1/query?lat=42.35&lon=13.4&maxradius=5.0&starttime=2016-01-01T00:00:00&endtime=2016-12-31T23:59:59&minmag=5&format=text&orderby=time-asc" 2>/dev/null  \
 | awk 'BEGIN { FS= "|" ; OFS= "|" }  \
     $13~/Rieti/||/Perugia/ {$13="\033[1;31m"$13"\033[0m"} \
     $11~/[0-9]+/ && $11 > 5.8 {$11="\033[1;33m"$11"\033[0m"} 
     {print  $1, $2, $5, $10, $11, $13 }' \
 | column -t -s '|'

ソートが正しくありません(図を参照)。

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

なぜ?どうすれば解決できますか?

修正する

私はこの質問を見たことがあります列コマンドとカラーエスケープコードに関する問題しかし、彼の答えはフルカラーラインの場合に適用されるので、私の問題を解決することはできません。

私の場合、次の理由で回答を適用または調整することはできません(またはできません)。

  1. 問題は、後続の列に関係なく、$ 11の列が着色された場合に制限されます。
  2. カラーコードを追加する良い方法やエレガントな方法は見えません。後ろに柱。
    テストのために列の出力をawkに送信する場合は、フィールドを適切に分離するようにawkに指示する方法がわかりません(フィールドがより多くのスペースで区切られている場合は正規表現を使用できますが、場合によっては区切りが単一のスペースで、awkフィールドを区切ります。記号で単語間のスペースとスペースを認識する方法がわかりません。

私が見ることができる唯一のことは、リセットカラーコードを割り当てから印刷ブロックに移動することです。最初出力専用バージョンのように、行間隔がより良いです(下の\033[0m2番目のコマンドラインの下線を参照)。 ここに画像の説明を入力してください。

ではどうやって解決しますか?私のように着色するよりエレガントな方法がありますか?

(私は知っています。Perlラインを使用するとより良いことができますが、問題があると思います。)

ベストアンサー1

この問題を解決するには3つの簡単な方法があります。

  1. 同じ長さを維持するには、常にこの列にエスケープシーケンスを使用してください。
  2. エスケープ文字を独自の列(追加の4列)に入れます。ただし、これにより、出力に余分なスペースが追加されます。
  3. column提案どおりにフォーマットしてください。

その他の注意事項はここにあります。ANSIエスケープコードを含む入力データを「表にする」ためのシェルツール

最初のオプションでは、\033[1;31mredだけを使用する代わりに\033[31;1mredを使用し、\033[31;0m前のコード、または同じシーケンスのコードも取り消す「赤ではない」、または通常のゼロコードを使用してください。これにより、すべての列のエスケープコードの長さが等しくなります。

BEGIN { FS=OFS="|" }  
function colour(ss,cc)    { return "\033[" cc ";1m" ss "\033[0m"; }
function notcolour(ss,cc) { return "\033[" cc ";0m" ss "\033[0m"; }
{  
  if ($13~/(RI|PG)/)    { $13=colour($13,31)    } 
                   else { $13=notcolour($13,31) }
  if (($11+0) > 5.8)    { $11=colour($11,33)    }
                   else { $11=notcolour($11,33) }
  print $1, $2, $5, $10, $11, $13 
}

(ソースデータの変更と一致するなど、いくつかのマイナーな簡略化と修正も上記に適用されました。)

このアプローチの問題は、column合計によって異なりますlibc。 (私はutil-linux-2.23.2から来ました。)印刷できないコンテンツが見つかった場合、column実際の幅ではなく戻りコードは-1になります。wcswidth()これは実際にテーブル形式を混乱させます。 util-linux-2.30.1 の最新バージョンは新しいバージョンを使用します。図書館問題を解決するが印刷できないコンテンツを16進符号化バージョンに置き換えてそれを行います。\xしたがって、元のエスケープが完全に失われます。 // エレガントでない方法で修正できます。

curl ... | awk ... | column -t -s '|' | while read -r line; do printf "$line\n"; done

printf脱出を説明する場所。同じ効果を得る\033には、独自のコードに置き換えることができます。\\x1bLinuxを使用しているかどうかはわかりません。 )

3番目のオプションでは、出力区切り記号の設定をcolumnサポートする必要があり、デフォルトは2つのスペースです。-o""に設定すると、|次のことができます。

curl ... | column -t -s "|" -o "|" | awk '
BEGIN { FS="|" }  
function colour(ss,cc) { return sprintf("\033[%i;1m%s\033[0m",cc,ss) }
{  
  if ($13~/(RI|PG)/) { $13=colour($13,31) } 
  if (($11+0) > 5.8) { $11=colour($11,33) }
  print $1, $2, $5, $10, $11, $13 
}'

ここでの秘密は、columnパイプで区切られた入力を使用することです。そして出力すると、幅が固定され、awkすべての重要なスペースを保存しながらを使用して安全に処理できます。columnサポートしていない場合は、-o以下を使用して偽にすることができます。

curl ... | sed -e 's/|/^|/g' | column -t -s^ | awk ...

これは区切り文字を " ^|"に倍増し、をcolumn使用し^、awkusesを使用します|。これにより、仮説が^データに確実に存在しなくなります。ハードタブが機能する可能性があります。

今「理由」を知っていると思います。しかし、明確に申し上げれば、次のようになります。

  • columnstrlen()wcslen()/が端末に表示されている長さと一致しないオクテット(または文字)を素早く計算できます
  • column長さを計算するために使用することisprint()ができ、端末エスケープにも正しくありません。
  • column印刷できないコンテンツが見つかると、すべての列が削除される可能性があります(私の場合と同じように)。

カラーコードシーケンスを削除することはかなり簡単な問題ですが、column

おすすめ記事