如何在bash中打印由TAB分隔的字符串?

Asu*_*Asu 9 bash putty whitespace tabs

我正在尝试打印由 TAB 分隔的两个字符串。我试过了:

echo -e 'foo\tbar'
printf '%s\t%s\n' foo bar
Run Code Online (Sandbox Code Playgroud)

他们都打印:

foo     bar
Run Code Online (Sandbox Code Playgroud)

两者之间的空格实际上是 5 个空格(根据在 Putty 中用鼠标选择输出)。

我也尝试过使用 CTRL+V 并在键入命令时按 TAB,结果相同。

强制将选项卡打印为选项卡的正确方法是什么,以便我可以选择输出并将其复制到其他地方,使用选项卡?

第二个问题:为什么 bash 将制表符扩展为空格?

更新:显然,这是 Putty 的问题:https : //superuser.com/questions/656838/how-to-make-putty-display-tabs-within-a-file-instead-of-changed-them-to -空格

ilk*_*chu 16

两者之间的空格实际上是 5 个空格。

不,这不对。不在echoor的输出中printf

$ echo -e 'foo\tbar' | od -c
0000000   f   o   o  \t   b   a   r  \n
0000010
Run Code Online (Sandbox Code Playgroud)

强制将选项卡打印为选项卡的正确方法是什么,以便我可以选择输出并将其复制到其他地方,使用选项卡?

这是一个不同的问题。这与外壳无关,而是与终端模拟器有关,它将制表符转换为输出中的空格。很多,但不是所有人都这样做。

将带有制表符的输出重定向到文件并从那里复制它可能更容易,或者unexpand在输出上使用以将空格转换为制表符。(尽管它也不知道什么是制表符开头的空格,如果可能的话,会将所有空格都转换为制表符。)这当然取决于您需要对输出做什么。

  • @Asu 我想他明白这一点。他的解决方案是通过其他方式获取输出,因为当您在窗口中选择选项卡时,终端仿真器不能保证将选项卡保留为选项卡。然而,我刚刚检查了一下,虽然 putty、xterm 和 konsole 将制表符转换为空格,但 urxvt 和 gnome-terminal 却不会。所以,另一个解决办法就是切换终端。 (2认同)
  • @Asu,是的,我想过手动解决这个问题。必须这样做会很烦人,但我承认我没有意识到有终端模拟器确实支持复制选项卡。改成这样,当然是一个更好的解决方案! (2认同)

JoL*_*JoL 9

就像 ilkkachu 所说的那样,这不是 bash 的问题,而是终端模拟器的问题,它将制表符转换为输出中的空格。

检查不同的终端,putty、xterm 和 konsole 将制表符转换为空格,而 urxvt 和 gnome-terminal 则不会。因此,另一种解决方案是切换终端。

  • 它也可以在你运行 `stty tab3` 后由 tty 驱动程序完成。 (4认同)

Sté*_*las 5

printf '%s\t%s\n' foo bar,printf输出foo<TAB>bar<LF>

fobar是单宽度的图形的字符。

接收到这些字符后,终端将显示相应的字形并将光标向右移动一列,除非它已经到达屏幕的右边缘(原始电传打字机中的纸张)),在这种情况下,它可能会换行并返回到屏幕的左边缘(换行)或根据终端及其配置方式丢弃该字符。

<Tab><LF>是两个控制字符。<LF>(又名换行符)是 Unix 文本中的行分隔符,但对于终端,它只提供一行(将光标向下移动一个位置)。所以内核中的终端驱动程序实际上会将其转换为<CR>(返回到屏幕的左边缘),<LF>(光标向下)(stty onlcr通常默认情况下打开)。

<Tab> 告诉终端将光标移动到下一个制表位(在大多数终端上默认情况下相距 8 个位置,但也可以配置为设置在任何位置)而不用空格填充间隙。

因此,如果将这些字符发送到带有每 8 列制表位的终端,而光标位于空行的开头,则将导致:

foo     bar
Run Code Online (Sandbox Code Playgroud)

打印在屏幕上的那一行。如果在光标位于包含 的行中的第三个位置时发送它们xxxxyyyyzzzz,将导致:

xxfooyyybarz
Run Code Online (Sandbox Code Playgroud)

在不支持制表的终端上,可以配置终端驱动程序将这些制表符转换为空格序列。( stty tab3).

原始电传打字机中的 SPC 字符会将光标移至右侧,而退格 ( \b) 会将其移至左侧。现在在现代终端中,SPC 向右移动并擦除(如您所愿写入空格字符)。所以吊坠\b必须是比 ASCII 更新的东西。在大多数现代终端上,它实际上是一个字符序列:<Esc>, [, C

有更多的转义序列可以将n字符向左、向右、向上、向下或在屏幕上的任何位置移动。还有其他转义序列可以擦除(填充空白)部分行或屏幕区域等。

那些序列通常用于通过视觉应用程序,如vilynxmuttdialog其中文本在屏幕上的任意位置写入。

现在,所有 X11 终端仿真器和其他一些非 X11 仿真器(如 GNU)都screen允许您选择屏幕区域进行复制粘贴。当您选择在vi编辑器中看到的部分内容时,您不想复制已用于生成该输出的所有转义序列。您想选择在那里看到的文本。

例如,如果您运行:

printf 'abC\rAC\bB\t\e[C\b\bD\n'
Run Code Online (Sandbox Code Playgroud)

它模拟,你进入编辑器会话abC,回到开始,替换abACCB,移动到下一个制表位,再得一列到右侧,然后两个列到左边,然后输入D

你看:

ABC    D
Run Code Online (Sandbox Code Playgroud)

即,ABC4 列间隙和D

如果您用鼠标选择xtermputty,它们将在选择中存储ABC4 个空格字符和D,而不是abC<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<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',将保留不可见的尾随空间。Or when selecting two lines doesn't include a LF character when the two lines result from wrapping at the right margin.

现在,如果您想将 的输出存储printf到 CLIPBOARD X11select 中,最好直接使用:

printf 'foo\tbar\n' | xclip -sel c
Run Code Online (Sandbox Code Playgroud)

请注意,当您将其粘贴到xterm或大多数其他终端中时,xterm实际上将其替换为\n\r因为这是xterm您按下时发送的字符Enter(并且终端驱动程序可能会将其转换回\n)。