除了`>>`以外,还有另一种简单的方法可以将行附加到文件末尾吗?


21

最近,我在tree_hole文件中回覆了简短的句子。

我曾经echo 'something' >> tree_hole用来做这项工作。

但是我总是担心如果我输入的>不是而不是怎么办>>,因为我经常这样做。

因此,我在bashrc中制作了自己的全局bash函数:

function th { echo "$1" >> /Users/zen1/zen/pythonstudy/tree_hole; }
export -f th

但是我想知道是否还有另一种简单的方法可以将行添加到文件末尾。因为我可能需要在其他场合经常使用它。

有没有?


9
您会不会忘记每次输入>都在使用变通方法?有了别名后rm="rm -i",在另一个环境中写了rm *等待确认问题的信。您正在学习危险习惯!
Walter A

9
@WalterA er,他的“解决方法”不允许他键入>而不是>>,而只是运行“ th some_sentence”,如果别名未定义,则不执行任何操作。
Random832

1
@ Ranom832适用于他的解决方法。警告是针对像noclobber这样的“解决方案”。当他在常规外壳中使用像noclobber之类的东西时,如果他是临时root并且想要附加某些东西,则可以使用>。
Walter A

7
@ Random832&WalterA我看到它时通常不会对此说什么,但我认为偶尔会发出友好的通知可能会有用。Zen的用户个人资料没有太多细节,所以我不确定您是否真的知道他的“替代方法”是正确的形式。也许您应该说出他们的“解决方法”OP的“解决方法”。也许你知道禅个人,因此,你知道,是正确的,在这种情况下,请原谅噪音。没什么大不了的,我只提到它是因为我知道如果您使用该表格来谈论我,我不会非常感激。
Celada

1
@Zen,您写道您担心误输入>而不是>>。Celada的计划将消除您环境中的风险,并且是您的理想解决方案。当您在帮助您的邻居(没有noclobber或使用ksh的邻居)并且对一个或两个>字符失去注意力时,您可能会意外覆盖他的一个文件。因此,每当您在自己的环境中收到夜色警告时,都要感谢上帝或Celada对自己说:哦,请小心!,摇摇头,等待两秒钟。
Walter A

Answers:


47

设置外壳的noclobber选项:

bash-3.2$ set -o noclobber
bash-3.2$ echo hello >foo
bash-3.2$ echo hello >foo
bash: foo: cannot overwrite existing file
bash-3.2$ 

3
这是绝对的答案。请注意,如果使用强制将其覆盖,则仍然可以覆盖该文件>|zsh默认情况下启用此行为。
Orion

1
@orion如何在zsh中启用/禁用它?我不记得明确禁用它,但是覆盖在我的zsh上可以正常工作。
muru

2
setopt noclobbersetopt clobber。看来它并非完全是“默认”,它取决于发行版随附的配置文件。
Orion

@muru应该适用set [+-]C于任何现代外壳
mikeserv

3
@Zen扑面而来set +o noclobber,或者set +C
Ruslan 2015年

7

如果您担心文件会被>操作员损坏,则可以将文件属性更改为仅追加:
ext2 / ext3 / ext4文件系统中:chattr +a file.txt
XFS文件系统中:echo chattr +a | xfs_io file.txt

如果您想要一个函数,我已经为自己创建了一个函数(我在服务文件中使用了它来记录输出),可以根据需要进行更改:

# This function redirect logs to file or terminal or both!
#@ USAGE: log option data
# To the file     -f file
# To the terminal -t
function log(){
        read -r data       # Read data from pipe line

        [[ -z ${indata} ]] && return 1    # Return 1 if data is null

        # Log to /var/log/messages
        logger -i -t SOFTWARE ${data}

        # While loop for traveling on the arguments
        while [[ ! -z "$*" ]]; do
                case "$1" in
                        -t)
                                # Writting data to the terminal
                                printf "%s\n" "${data}"
                                ;;
                        -f) 
                                # Writting (appending) data to given log file address
                                fileadd=$2
                                printf "%s %s\n" "[$(date +"%D %T")] ${data}" >> ${fileadd}
                                ;;
                        *)
                                ;;
                esac
                shift           # Shifting arguments
        done
}

2
该脚本存在一些问题。1)通常应在参数扩展名(以开头的东西$)两边加上双引号,以防止出现乱码,单词拆分和相关的空格问题。在线ShellCheck应用程序可以在bash脚本中捕获此问题以及其他各种问题。与此相关的"$@"低于安全$*
下午15年

3
2)通常,您应该read使用-r选项来调用该命令,以防止输入中的任何反斜杠转义以下字符。3)在bash脚本中,脚本变量名称通常使用小写字母,因为ALL UPPER CASE用于系统变量。因此,如果对自己的变量使用大写字母,则会使阅读代码的人感到困惑,并且可能会无意中破坏您想在脚本稍后使用的系统变量。并且,如果您获取脚本的源代码,它将破坏后续命令的变量。
下午15年

3
4)echo对于打印固定字符串很方便,但是它可以对任意数据执行意外操作,尤其是在GNU系统上。这是迄今为止使用更安全printf。有关更多信息,请参见unix.stackexchange.com/questions/65803/…,尤其是StéphaneChazelas的答案。
下午15年

3
@PM 2Ring,今天我从您那里学到了很多东西,非常感谢..我会尽快修复它们。
Sepahrad Salour 2015年

1
干得好,塞帕拉德!
下午

3

使用tee与附加选项:

foo | tee -a some-file
# or
tee -a some-file <<EOF
blah blah
EOF
# or 
tee -a some-file <<<"blah blah"

5
好主意,+ 1,但是我想如果OP担心忘记>角色,那么他们可能会担心忘记-a选项!
Celada

@Celada我想是这样(但是我猜错了一组重复的击键中的一个击键而不是错了而不是忘记了一个选项)。
muru

0

许多可以打开文件进行覆盖的程序也可以打开它们进行追加,例如gnu dd。

dd conv=notrunc oflag=append of=file

它可以读取stdin或在if= 参数add中命名的文件以2>/dev/null抑制字节数。


3
这是一个好主意™张贴的答案之前,测试你的代码...
PM 2Ring

1
推荐dd是一个坏主意。dd不会可靠地将其输入写入其输出,而不是当其中之一不是常规文件或块设备时
吉尔斯'SO-不再是邪恶的

@gilles,您在该链接处提供的信息是错误的,如果未指定count,则dd将复制所有可用数据,就像cat一样。
Jasen 2015年

-1

我想使用sed(即使使用备份副本,也请参阅后面的扩展-i):

sed -i.bak '$ a\something' /Users/zen1/zen/pythonstudy/tree_hole

我为什么不感到惊讶...你是个疯子,科斯塔斯。:)(恭维,顺便说一句)
下午15年

@ PM2Ring是的,我非常危险!:P
Costas

当然,有效的方法是制作文件副本,将新文本添加到末尾,然后删除原始文件并将副本重命名为原始名称。如果您对目录没有写访问权,则此(1)不起作用;(2)断开链接;如果该文件较大,则(3)会占用大量资源。有趣的是,提到了“危险”一词!
G-Man说'恢复莫妮卡'

-1

您始终可以通过其他方式搜索文件...

seq 10000000 >f
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
wc -l f; tail f

...看起来奇怪的序列打印:

10000000
10000001
10000002
10000003
10000004
10000005 f
9999996
9999997
9999998
9999999
10000000
new line!
new line!
new line!
new line!
new line!

但这有点愚蠢。

一个更有用的示例如下所示:

 apnd() if    shift
        then  wc -l  >&2
              printf "$@"
        fi    <>"$1" >&0

您可以这样称呼它:

 apnd /path/to/file          \
      "${printf_fmt_string}" \
       arbitrary list of strings

最后,您会在执行追加操作之前file写入的行数stderr

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.