BashでTABで区切られた文字列を印刷するには?

BashでTABで区切られた文字列を印刷するには?

タブで区切られた2つの文字列を印刷しようとしています。私は試した:

echo -e 'foo\tbar'
printf '%s\t%s\n' foo bar

両方印刷:

foo     bar

2つの間のスペースは実際には5つのスペースです(Puttyのマウス選択出力に基づいて)。

また、Ctrl + Vを使用してコマンドを入力している間にTabキーを押しても同じ結果が出ました。

出力を選択し、タブを使用して別の場所にコピーできるように強制的にタブに印刷する正しい方法は何ですか?

2番目の質問:Bashがタブをスペースに拡張するのはなぜですか?

修正する:明らかにこれはPuttyの問題です。 https://superuser.com/questions/656838/how-to-make-putty-display-tabs-within-a-file-instead-of-chang-them-to-spaces

答え1

2つの間のスペースは実際には5マスです。

いいえ、そうではありません。echoまたはの出力にはありませんprintf

$ echo -e 'foo\tbar' | od -c
0000000   f   o   o  \t   b   a   r  \n
0000010

出力を選択し、タブを使用して別の場所にコピーできるように強制的にタブに印刷する正しい方法は何ですか?

これは別の質問です。これはシェルとは関係ありませんが、出力のタブ文字を空白に変換する端末エミュレータに関連しています。多くの(すべてではありませんが)人々がそうします。

タブ付きの出力をファイルにリダイレクトし、そこからコピーしたり、unexpand出力からスペースをタブに変換したりするのは簡単です。 (空白がタブで始まり、可能であればすべてタブに変換されるという事実もわかりませんが)、これはもちろん出力として実行する必要がある操作によって異なります。

答え2

ilkkachuが言ったように、これはbashの問題ではなく、出力のタブを空白に変換する端末エミュレータの問題です。

他の端末をチェックすると、putty、xterm、konsoleはタブを空白に変換しますが、urxvtとgnome-terminalはそうではありません。したがって、別の解決策は、端末を切り替えることです。

答え3

ではprintf '%s\t%s\n' foo barprintf出力しますfoo<TAB>bar<LF>

f、、、oおよびbは単一a角度rグラフィック文字です。

これらの文字を受信すると、端末はその文字を表示し、カーソルが画面の右端(元のテレタイプ機械の用紙)に達しない限り、右に1列移動します。この場合、行を入力できます。端末と設定方法に応じて、画面の左端に戻るか(改行)文字を削除します。

<Tab>そして<LF>2つコントロール数値。<LF>(改行とも呼ばれます)はUnixテキストの行区切り文字ですが、端末では行を分割するだけです(カーソルを1つの位置より下に移動します)。したがって、カーネルのターミナルドライバは実際には<CR>(画面の左端に戻る)、<LF>(カーソルの下に移動)(stty onlcr通常はデフォルトでオン)に変換します。

<Tab>スペースをスペースで埋めることなく、カーソルを次のタブストップに移動するように端末に指示します。

したがって、カーソルが空白行の先頭にある間に8列ごとにタブで停止する端末にこれらの文字を送信すると、次のような結果になります。

foo     bar

画面に印刷された行。カーソルがインクルードラインの3番目の位置にある間に送信されると、xxxxyyyyzzzz次の結果が得られます。

xxfooyyybarz

タブをサポートしていない端末では、これらのタブ文字を一連の空白に変換するように端末ドライバを構成できます。 (stty tab3)。

元のテレタイプのSPC文字はカーソルを右に移動し、バックスペースキー(\b)はカーソルを左に移動しました。最新の端末では、SPCは右に移動して消去されます(予想どおりに空白文字を書き込みます)。したがって、ペンダントは\bASCIIより新しいものでなければなりません。ほとんどの最新の端末では、実際には、、<Esc>[ような一連の文字ですC

n文字を左、右、上、下、または画面のどこにでも移動できる、より多くのエスケープシーケンスがあります。行や画面領域などの一部を消去できる(スペースを埋める)他のエスケープシーケンスがあります。

viこれらのシーケンスはlynx、、、などの視覚的アプリケーションで一般的に使用されます。muttここで、dialogテキストは画面上のどこにでも記録されます。

すべてのX11端末エミュレータと他のX11以外の端末エミュレータ(GNUなど)では、screenコピーして貼り付ける画面領域を選択できるようになりました。エディタに表示されるコンテンツの一部を選択するときは、そのvi出力を生成するために使用されたすべてのエスケープシーケンスをコピーしたくありません。そこに見えるテキストを選択したいです。

たとえば、次を実行する場合:

printf 'abC\rAC\bB\t\e[C\b\bD\n'

abCを入力して最初に戻り、に置き換え、次のabタブストップにAC移動し、右に1列、左に2列を入力し、を入力するエディタセッションをシミュレートします。CBD

望むより:

ABC    D

つまり、ABC4つの列間隔とD

xtermマウスでまたはを選択すると、putty選択項目にはABC4つの空白文字が保存されます。DabC<CR>AC<BS>B<Tab><Esc>[C<BS><BS>D

最終的に選択されるのは、printfターミナルドライバとターミナルエミュレータが送信したが後処理されたものです。

他の種類の変換については、変更<U+0065><U+0301>e次にアクセントの組み合わせ)を<U+00E9>é事前合成形式)で参照してくださいxterm

またはecho abc最終的にはABCターミナルドライバによって変換されますstty olcuc

<Tab>Likeは、テキストファイル(MSDOSテキストファイルでも時々改ページに使用されます)で<LF>実際に時々見つかる数少ない制御文字の1つです。<CR><FF>

したがって、一部の端末エミュレータは、可能であればコピー/貼り付けバッファにコピーして保存するように選択します(ただし、通常はそうではありません<CR><LF>

gnome-terminalたとえば、VTEベースの端末(VTEなど)で空白行の出力を選択すると、X11選択が実際に7スペースの代わりにX11選択に格納されることがわかります。printf 'a\tb\n'gnome-terminala\tbab

ただし、 の出力については空白 6 つの合計をprintf 'a\t\bb\n'保存し、出力の場合は空白 7 つの合計を保存します。abprintf 'a\r\tb\n'ab

それ以外の場合、端末は実際の入力をコピーしようとします。たとえば、実行後に2行を選択すると、printf 'a \nb\n'見えない末尾のスペースが残ります。または、LF文字を含まない2行を選択した場合、2行が右マージンで改行された結果である場合。

printfCLIPBOARD selectの出力を保存するには、X11次のように直接実行することをお勧めします。

printf 'foo\tbar\n' | xclip -sel c

xtermこれをまたは他のほとんどの端末に貼り付けると、実際にはを押したときに送信された文字であるためにxterm置き換えられます(ターミナルドライバはそれを再変換できます)。\n\rxtermEnter\n

関連情報