bash - bash 重定向到文件添加了意外的 0A 字节
问题描述
我认为如果我将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
如果它被重定向,行为会有所不同。你可以得到你期望的输出-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 向我们指出ls 的 POSIX 规范,内容如下
默认格式应为每行列出一个条目到标准输出;例外情况是终端或指定了 -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;
或者在当前的 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);
wherestdout_isatty
的定义与前面的示例相同。
推荐阅读
- django - 获取Django模型对象后进行数据转换
- python - Gmail API - 从 g-suite 服务帐户发送邮件时设置发件人名称
- node.js - 用fluent-ffmpeg创建GIF,覆盖不显示?
- list - 将整个数据列表插入到 xamarin.android 中的 sql 数据库表中
- sql - 查找最流行的 SQL 组合
- mongodb - 如何从 mongo 领域应用程序中导出当前应用程序用户?
- flutter - 如何根据 --dart-define 参数构建具有不同图标的 Flutter 应用程序
- asp.net - Ocelot + consul + my web api (.Net 5) via HTTPS in docker
- macos - 创建devcontainer时如何获取ARM Docker镜像是VS Code?(麦克米1)
- json - 在这种加密数据的情况下,什么是 devideId?