我通常使用以下方法附加到文本文件cat
:
cat >> FILE
我使用别名来避免意外覆盖文件(使用单个>
):
alias a='cat >>'
Enter 更改行,Ctrl+D终止命令。我在主文件夹中写入多个文本文件,所有这些文件都是我创建、拥有并可以编辑的。
有几次,在我的桌面 Linux 系统 (Fedora 39) 和 Termux (Android) 上,命令停止重定向到文件,同时看似正常地接受输入。我丢失了数百行,主要是我粘贴的 URL。似乎仅在命令运行一段时间后才会发生。
是否有任何原因导致重定向cat >>
可能停止运行?例如,任何特殊字符(在输入中)是否会产生影响?
更新:我已经确认各个文件的 inode 编号不断变化($ ls -li
或者使用 来查看确切时间$ stat -c '%w'
)——这种情况发生因为 Syncthing 的设计会重新创建同步文件。我将来必须重新评估我如何使用该软件。抱歉一开始没有提到 Syncthing。
在我自动化的命令中,至少sed -i
(就地编辑文件)也替换了索引节点。
该命令cat >> FILE
也需要更换(已给出建议,请参阅评论和答案)。
答案1
运行后cat >> file
,shell 将在fd 1 上的子进程中的file
当前工作目录中打开,如果成功则在该进程中执行。O_WRONLY|O_CREAT|O_APPEND
cat
如果没有,shell 将输出错误消息并且不运行cat
。
如果找不到cat
命令,它也会输出一条错误消息。
cat
依次,在循环中读取其 fd 0 并将其读取的内容写入 fd 1。
同样,如果失败,它将输出一条错误消息。
如果正在运行的进程cat
被信号杀死或挂起,shell 还应该在 stderr 上报告它(例如超出文件大小限制如果用SIGXFSZ
或杀死暂停(tty 输入)如果通过 SIGTTIN 暂停)。
如果 fd 0 在 tty 设备上打开,并且该 tty 设备是相同的,则 shell 从中读取命令,通常是这种情况,在运行之前cat
,shell 将按照进入其自己的行编辑器之前的方式配置 tty 的行规则。
一般来说,这意味着它将处于icanon
行规则实现粗略行编辑器的模式。
在所有这些中,行编辑器实际上是唯一能够识别特殊字符的东西。stty -a
会给你一个清单。就我而言:
$ stty -a
speed 38400 baud; rows 43; columns 159; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc
你会看到icanon
上面提到的。^C
, ^\
, ^?
, ^U
, ^D
, ^Q
, ^S
, , ^Z
, ^R
, ^W
,字符经过特殊处理。//受制于(在我的情况下已启用),/受制于,(上面)在 Linux 上不受支持。^V
^O
^C
^Z
^\
isig
^S
^Q
ixon
discard
^O
例如,如果您输入foobar^Ubaz
,foobar
则为被杀,但话又说回来,您会看到它在您键入的回声中被删除。
输入^C
角色会cat
在其中间杀死read
。
但如今大多数终端模拟器在粘贴时都会删除这些字符。因此,为了在粘贴时发生这种情况,您需要使用一个仍然不执行剥离操作的终端,或者将其中一些kill
/ werase
/ intr
... 设置设置为一些非控制字符,这将是病理状况。
该行编辑器对其可以编辑的行的大小也有限制。在 Linux 上,IIRC 为 4095 字节。因此,如果您粘贴的行大于此值,则超过第 4095 个字节的任何内容都将被丢弃。
在该icanon
模式下,当 tty 行编辑器退出时, cat
's将返回,当您输入(将其转换为on ) 或或 任何,或字符read()
时,就会发生这种情况。^M
^J
icrnl
^J
eol
eol2
eof
但无论如何,如果cat
正常退出,也就是说,如果它没有被 SIGINT on^C
或 SIGQUIT on杀死,^\
或者没有被 SIGTSTP on 挂起^Z
,并且没有报告错误,那么它将从终端读取输入并将其写入文件。
因此,总而言之,您正在尝试的事情在正常情况下不应该发生,我能想到的唯一情况是病理情况:
- 所报告的 tty 设置
stty -a
全部被窃听。 - 或者您粘贴的数据包含由 tty 驱动程序的行编辑器解释的控制字符,并且由于某种原因您的终端编辑器不会删除它们。
cat
不要忽略人为错误,例如未能看到shell报告的错误或在与您想象的不同的目录中创建的文件,或者在cat
运行时删除、替换、重命名或截断(就像这样同步事物您在评论中提到使用)。
使用该a='cat >>'
别名,如果您输入a some file
而不是a 'some file'
,则它cat >> some file
与 相同,cat file >> some
并且cat
将读取file
而不是 stdin 并将输出写入some
而不是some file
。
对该别名的可能改进(假设 GNU tee
)是:
a() {
rlwrap -pblue -S 'add> ' tee --output-error=warn -a -- "$@" > /dev/null
}
Whererlwrap
为您提供了比原始 tty 驱动程序更高级的行编辑器(如果用作bash
shell,您已经熟悉了),并且有一个提示,可以更清楚地表明它正在等待一些输入。
并且使用tee
允许您一次将输入写入多个文件。
答案2
如果目的是避免意外覆盖文件,请考虑设置适当的 shell 变量。例如,对于bash
,
set -o noclobber # Do not allow > to overwrite a file
set -C # The same
例子
set -o noclobber
echo >ddd
echo >ddd
-bash: ddd: cannot overwrite existing file
set +o noclobber
echo >ddd