【问题标题】:bash redirection to file adds unexpected 0A bytesbash 重定向到文件添加了意外的 0A 字节
【发布时间】:2021-11-13 13:04:20
【问题描述】:

我认为如果我将 ls 的输出重定向到一个文件,那么本来会发送到控制台的完全相同的字符序列将被写入该文件。

为了测试,我创建了 3 个文件,然后列出它们

$ touch a b c
$ ls
a  b  c

我现在再次运行 ls,这次重定向到我 cat

的文件
$ ls > out
$ cat out
a
b
c
out

没想到在out的每个文件名之间多了一个0A的换行符

$ xxd out
00000000: 610a 620a 630a 6f75 740a                 a.b.c.out.

将 ls 的输出连接到 xxd

$ ls | xxd
00000000: 610a 620a 630a 6f75 740a                 a.b.c.out.

换行符仍然存在。

0A 字节是如何到达那里的?如果 ls 被重定向或者 shell 在某些情况下会忽略换行符,它的行为是否会有所不同?

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.3 LTS
Release:    20.04
Codename:   focal

【问题讨论】:

  • 试试ls | xxd....(或ls | cat
  • 尽管多年来一直依赖这种行为,但我什至从未注意到它:感谢您指出!
  • 管道到 xxd 是一个有趣的实验,我已经更新了一些问题

标签: bash io-redirection


【解决方案1】:

是的,ls 在被重定向时表现不同。你可以通过-x得到你期望的输出:

$ mkdir /tmp/t
$ cd /tmp/t
$ touch a b c
$ ls | cat
a
b
c
$ ls -x | cat
a b c
$ ls --format=single-column
a
b
c

@GordonDavisson 将我们指向POSIX spec for ls,其内容为

默认格式是每行列出一个条目到标准输出;例外情况是终端或指定了 -C、-m 或 -x 选项之一时。如果输出到终端,则格式是实现定义的。

因此,无论如何,在 POSIX 中,“规范”是逐行输出;终端输出可以是任何东西(尽管除了空格我从未见过任何东西)。大概这是为了使逐行迭代响应成为可能。我也从来没有注意到它,尽管依赖它很多次,但现在我开始思考它!

实施

这里是一个 ls 实现的源代码,明确检查:

    case LS_LS:
      /* This is for the `ls' program.  */
      if (isatty (STDOUT_FILENO))
        {
          format = many_per_line;
          /* See description of qmark_funny_chars, above.  */
          qmark_funny_chars = true;
        }
      else
        {
          format = one_per_line;
          qmark_funny_chars = false;
        }
      break;

source

或者在当前的 gnu coreutils 中:

  format = (0 <= format_opt ? format_opt
            : ls_mode == LS_LS ? (stdout_isatty ()
                                  ? many_per_line : one_per_line)
            : ls_mode == LS_MULTI_COL ? many_per_line
            : /* ls_mode == LS_LONG_FORMAT */ long_format);

其中stdout_isatty 的定义与前面的示例相同。

source

【讨论】:

  • 根据POSIX spec for ls:“默认格式应是每行列出一个条目到标准输出;例外是终端或-C-m之一或指定了-x 选项。如果输出到终端,则格式是实现定义的。”所以管道/重定向行为,“正常”行为在技术上是不标准化的。
  • @GordonDavisson 谢谢!我将在答案中添加(带有归属)
猜你喜欢
  • 2011-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-17
  • 1970-01-01
  • 2020-05-17
  • 2020-10-26
相关资源
最近更新 更多