web-dev-qa-db-ja.com

タブ区切りのテキストファイルをフィードし、各行を80文字にカットするコマンドはどれですか。

(場合によっては)タブ区切りのデータの複数行のテキストファイルがあります。ファイルを一目で確認できるように出力したいので、各行の最初の80文字だけを表示したいと思います(重要なものを各行の最初に配置するようにテキストファイルを設計しました)。

Catを使用してファイルの各行を読み取り、各行をパイプ内の次のコマンドに送信できると思いました。

cat tabfile | cut -c -80

しかし、それは壊れているように見えました。あちこち試してみたところ、grepは機能しているように見えましたが、機能しないことがわかりました(ファイルのすべての行に80文字以上あるわけではありません)。

私は試した:

cat tabfile | tr \t \040 | cut -c -80

それは私のデータを少し混乱させるでしょうが、空白の読みやすさを排除することによって。しかし、それはうまくいきませんでした。どちらもしませんでした:

cat tabfile | tr \011 \040 | cut -c -80

たぶん私はtrを間違って使用していますか?以前にtrで問題が発生し、複数のスペースを削除したいと思っていました(このマシンでアクセスできるtrのバージョンには、複数の文字を圧縮するための-sオプションがあります-もっと遊ぶ必要があるかもしれません)

私がいじり回した場合、Perl、awk、sed、またはこれを行うための何かを使用できると確信しています。

ただし、(POSIX?)通常のコマンドを使用するソリューションが欲しいので、可能な限り移植性があります。最終的にtrを使用する場合は、最終的にタブを文字に変換し、計算を実行し、計算を切り取ってから、それらの文字を出力用のタブに戻すことを試みます。

単一の行である必要はなく、コマンドラインで直接入力する必要もありません。スクリプトで問題ありません。


タブファイルの詳細:

いつか他のプログラムにデータをインポートしたいと思うかもしれないので、タブを使用してフィールドを分割します。そのため、コンテンツの間にタブが1つしかない傾向があります。ただし、プレーンテキストファイルを見たときに読みやすくするために、タブを使用して縦の列に揃えています。つまり、一部のテキストでは、次のフィールドを上下に並べてタブが機能する場所に到達するまで、コンテンツの最後にスペースを埋め込みます。

 DarkTurquoise#00CED1海、空、手漕ぎボート自然
 MediumSpringGreen#00FA9A樹木に便利マジック
ライム#00FF00春の鶏とフル$ 
でのみ使用
8
user3082

expandおよび/またはunexpandを探していると思います。 \tabの幅を1文字ではなく8文字としてカウントしようとしているようです。 foldもそれを行いますが、入力を切り捨てるのではなく、次の行にラップします。私はあなたが望むと思います:

expand < input | cut -c -80

expandunexpandは両方とも POSIXを指定

  • expandユーティリティは、ファイルまたは標準入力を標準出力に書き込み、\tab文字を1つ以上のスペースに置き換えます。次のタブストップにパディングするために必要な文字。 backspace文字はすべて出力にコピーされ、タブストップ計算の列位置カウントがデクリメントされます。列位置カウントはゼロ未満にデクリメントされません。

ものすごく単純。だから、これが何をするのか見てみましょう:

unset c i; set --;                                                             
until [ "$((i+=1))" -gt 10 ]; do set -- "$@" "$i" "$i"; done                      
for c in 'tr \\t \ ' expand;  do eval '                                           
    { printf "%*s\t" "$@"; echo; } | 
      tee /dev/fd/2 |'"$c"'| { 
      tee /dev/fd/3 | wc -c >&2; } 3>&1 |
      tee /dev/fd/2 | cut -c -80'
done

上部のuntilループは、次のような一連のデータを取得します...

1 1 2 2 3 3 ...

これは%*s引数パディングフラグでprintfsされるため、セット内の各printfは、引数の数と同じ数のスペースでパディングされます。それぞれに\tab文字を追加します。

すべてのteesは、適用された各フィルターの効果を示すために使用されます。

そして効果はこれらです:

1        2        3        4        5        6        7        8                9               10
1  2   3    4     5      6       7        8         9         10 
1  2   3    4     5      6       7        8         9         10 
66
1        2        3        4        5        6        7        8                9               10
1        2        3        4        5        6        7        8                9               10 
1        2        3        4        5        6        7        8                
105

それらの行は次のように2つのセットに並んでいます...

  1. printf ...; echoの出力
  2. tr ...またはexpandの出力
  3. cutの出力
  4. wcの出力

上部の4行はtrフィルターの結果です。各\tabは単一のspaceに変換されます。

そして、下の4つはexpandチェーンの結果です。

9
mikeserv

タブは区切りよりも位置合わせのためのものであるため、1つの方法はcolumnを使用してからcutを使用することです。

column -s '\t' -t <some-file | cut -c -80

columnはPOSIXではないようです。 UbuntuのBSDユーティリティの一部であるため、かなりクロスプラットフォームであると思います。

3
muru

コメントでのドンの提案は良いスタートでした。

これは私がそれを(ほとんど)動作させるために必要なものです:

pr +1 -1 -t -m -l1000 -w 80 tabfile

-mフラグを単一の列で有効にするには、-wが必要でした。マニュアルページはそれを示すためにいくつかの書き直しを使用できます。

回避策を試したところ、pr\t文字を出力することがわかりました。その結果をcutに供給すると、同じ問題が発生しました。

-1(列フラグ)は、manページで具体的に次のように述べています。

このオプションは、-mと一緒に使用しないでください。

ただし、このオプションを使用しない場合、prは指定された長さよりはるかに短い長さで行を完全に切り捨てます。

prは、フィールド内のすべてのWordの前(または後)にもスペースを挿入します(つまり、1つのスペースがあるすべての場所、処理後は2つのスペースがあります)。単語が多すぎる場合、挿入されたスペースは-w制限を無視します(ラップアラウンドを作成します)。しかし、奇妙なことに、タブで区切られていない(つまり、空白が配置されている)「列」は整列したままです。

1
user3082

本当に表示幅を意識する必要があるユーティリティの1つはfoldです。残念ながら、折り返す代わりに破棄するオプションがないようです。それは恐らく非効率的ですが、しかしあなたは次のようなことをすることができます

while read -r line; do fold -w80 <<< "$line" | head -n1; done < file
0
steeldriver

awkの使用:

awk '{ $0 = substr($0, 1, 80) }1' file

ここでのクリス・ダウンの答え に基づく。

0
jasonwryan