我正在尝试打印由 TAB 分隔的两个字符串。我努力了:
echo -e 'foo\tbar'
printf '%s\t%s\n' foo bar
他们都打印:
foo bar
两者之间的空格实际上是 5 个空格(根据在 Putty 中使用鼠标选择输出)。
我也尝试过在输入命令时使用 CTRL+V 并按 TAB,结果相同。
强制标签打印为标签的正确方法是什么,所以我可以选择输出并将其复制到其他地方,带有标签?
第二个问题:为什么 bash 将制表符扩展到空格?
更新:显然,这是腻子的问题: https ://superuser.com/questions/656838/how-to-make-putty-display-tabs-within-a-file-instead-of-changing-them-to -空格
不,这不对。不在
echo
or的输出中printf
。这是一个不同的问题。这与 shell 无关,而是与终端仿真器有关,它在输出时将制表符转换为空格。许多人,但并非所有人都这样做。
将带有制表符的输出重定向到一个文件,然后从那里复制它,或者
unexpand
在输出上使用将空格转换为制表符可能会更容易。(虽然它也不知道制表符的开头是什么空格,并且如果可能的话,会将所有空格都转换为制表符。)这当然取决于您需要对输出做什么。就像 ilkkachu 所说,这不是 bash 的问题,而是终端仿真器将制表符转换为输出时的空格。
检查不同的终端,putty、xterm 和 konsole 将制表符转换为空格,而 urxvt 和 gnome-terminal 不会。因此,另一种解决方案是切换终端。
在
printf '%s\t%s\n' foo bar
,printf
做输出foo<TAB>bar<LF>
。f
,o
,b
,a
和r
是单角图形字符。收到这些字符后,终端将显示相应的字形并将光标向右移动一列,除非它已经到达屏幕的右边缘(原始远程打字机中的纸张)),在这种情况下它可能会输入一行并返回到屏幕的左边缘(换行)或只是丢弃字符,具体取决于终端及其配置方式。
<Tab>
是<LF>
两个控制字符。<LF>
(又名换行符)是 Unix 文本中的行分隔符,但对于终端,它只输入一行(将光标向下移动一个位置)。所以内核中的终端驱动程序实际上会将其翻译为<CR>
(返回屏幕左边缘),<LF>
(光标向下)(stty onlcr
一般默认开启)。<Tab>
告诉终端将光标移动到下一个制表位(在大多数终端上,默认情况下相隔 8 个位置,但也可以配置为在任何位置设置)而不用空白填充间隙。因此,如果将这些字符发送到每 8 列带有制表位的终端,而光标位于空行的开头,则会导致:
打印在该行的屏幕上。如果在光标位于包含 的行中的第三个位置时发送它们
xxxxyyyyzzzz
,则将导致:在不支持制表的终端上,可以将终端驱动程序配置为将这些制表符转换为空格序列。(
stty tab3
)。原始远程打字机中的 SPC 字符会将光标向右移动,而退格 (
\b
) 会将光标向左移动。现在在现代终端中,SPC 向右移动并擦除(如您所料写入空格字符)。所以 的吊坠\b
必须是比 ASCII 更新的东西。在大多数现代终端上,它实际上是一个字符序列:<Esc>
,[
,C
.有更多的转义序列可以将
n
字符向左、向右、向上、向下或在屏幕上的任何位置移动。还有其他转义序列可以擦除(填充空白)部分行或屏幕区域等。这些序列通常由诸如
vi
,lynx
,之类的视觉应用程序使用mutt
,dialog
其中文本被写在屏幕上的任意位置。现在,所有 X11 终端仿真器和一些其他非 X11 仿真器(如 GNU)
screen
都允许您选择屏幕区域进行复制粘贴。当您选择您在编辑器中看到的部分内容时vi
,您不想复制所有用于生成该输出的转义序列。您想选择在那里看到的文本。例如,如果您运行:
它模拟了一个编辑器会话,您在其中输入
abC
,回到开头,替换ab
为AC
,C
替换为B
,移动到下一个制表位,然后再向右一列,然后向左两列,然后输入D
。你看:
也就是说,
ABC
4 列间隙和D
。如果您用鼠标在
xterm
or中选择它putty
,它们将在选择中存储ABC
4 个空格字符D
,而不是abC<CR>AC<BS>B<Tab><Esc>[C<BS><BS>D
。printf
最终选择的是终端驱动程序和终端仿真器已发送但经过后处理的内容。对于其他类型的转换,请参阅
<U+0065><U+0301>
(e
后跟一个组合的重音) 更改为<U+00E9>
(é
预组合形式) byxterm
。或者
echo abc
最终ABC
由终端驱动程序翻译,然后再发送到终端stty olcuc
。现在,
<Tab>
, like<LF>
是文本文件中有时会出现的少数控制字符之一(也在<CR>
MSDOS 文本文件中,有时<FF>
用于分页符)。<CR>
因此,一些终端仿真器确实选择在可能的情况下将它们复制到复制粘贴缓冲区中以保留它们(通常情况并非如此<LF>
)。例如,在基于 VTE 的终端(如
gnome-terminal
)中,您可能会看到,当您选择printf 'a\tb\n'
空行上的输出时,gnome-terminal
实际上存储a\tb
在 X11 选择中,而不是a
、7 个空格和b
。但是对于 的输出
printf 'a\t\bb\n'
,它存储a
, 6 个空格和b
, 并且对于printf 'a\r\tb\n'
,a
, 7 个空格和b
。在其他情况下,终端会尝试复制实际输入,例如当您在运行后选择两行时,
printf 'a \nb\n'
将保留不可见的尾随空格。或者选择两行时,当两条线在右边边缘包裹时不包括LF字符。现在,如果要将输出存储
printf
到 CLIPBOARDX11
选择中,最好直接这样做:请注意,当您将其粘贴到
xterm
或大多数其他终端中时,xterm
实际上会将其替换为\n
,\r
因为这是xterm
您按下时发送的字符Enter(终端驱动程序可能会将其翻译回\n
)。