我想添加一个运算符(例如^>)来处理prepend而不是追加(>>)。 我需要修改Bash源文件还是有更简单的方法(插件等)?
^
是字符的一个可怜的选择,因为它在历史替换已经被使用了。
要将新的重定向类型添加到shell语法,请从parse.y
开始。 将其声明为一个新的%token
以便它可以被使用,将其添加到STRING_INT_ALIST other_token_alist[]
以便它可以出现在输出中(例如错误消息),更新解析器中的redirection
规则,并更新词法分析器以发出令牌遇到适当的字符。
command.h
包含重定向类型的enum r_instruction
,这将需要扩展。 make_redirection
中的make_cmd.c
有一个巨大的switch
语句,处理重定向指令,实际的重定向由redir.c
的函数执行。 分散在源代码的其余部分中的是打印,复制和销毁管线的各种功能,这些管线也可能需要更新。
就这样! Bash并不是那么复杂。
这没有讨论如何实现预定义的重定向,这将是困难的,因为UNIX文件API只提供附加和覆盖。 前置到一个文件的唯一方法是完全重写它,这与其他答案一样,比任何现有的shell重定向都要复杂得多。
首先,你需要修改bash源代码并且相当重要。 因为,最重要的是,你很难实现。
请注意,bash重定向操作符通常会执行一个非常简单的写操作,并且只在单个文件(或者管道的情况下)上工作。 排除非常具体的解决方案,通常无法写入文件的开头,因为每次写入后需要将所有剩余内容向前移动。 你可以尝试这样做,但这将会很困难,非常无效(因为每个写操作都需要重写整个文件),而且非常不安全(因为出现任何错误,最终都会随机混合使用新旧版本)。
也就是说,如果像其他人那样使用临时文件的功能或者其他解决方案,你的确可能会更好。
为了完整性,我自己实现:
prepend() { local tmp=$(tempfile) if cat - "${1}" > "${tmp}"; then mv "${tmp}" "${1}" else rm -f "${tmp}" # some error reporting fi }
请注意,与@jpa建议的不同,您应该将连接的数据写入临时文件,因为该操作可能会失败 ,如果这样做,则不希望丢失原始文件。 之后,您只需用新文件替换旧文件,或者删除临时文件并按照您的喜好处理故障。
简介与其他解决方案相同:
echo test | prepend file.txt
和一些修改后的版本来保留权限和符合链接安全(如果有必要的话)就像>>
一样:
prepend() { local tmp=$(tempfile) if cat - "${1}" > "${tmp}"; then cat "${tmp}" > "${1}" rm -f "${tmp}" else rm -f "${tmp}" # some error reporting fi }
只要注意这个版本实际上是不太安全的,因为如果在第二个cat
别的东西会写入到磁盘并填充它,那么最终会得到不完整的文件。
说实话,如果有必要,我不会亲自使用它,而是处理符号链接和重置外部权限。
添加一个操作符可能相当困难,但也许一个函数可能就足够了?
function prepend { tmp=`tempfile`; cp $1 $tmp; cat - $tmp > $1; rm $tmp; }
使用示例:
echo foobar | prepend file.txt
将文本“foobar”前置到file.txt中。
我认为bash的插件体系结构(通过“启用”内置命令加载共享对象)仅限于提供附加的内置命令。 重定向操作符是运行简单命令的语法的一部分,所以我认为您需要修改解析器来识别和处理新的^>
运算符。
大多数Linux文件系统不支持预先配置。 事实上,我不知道任何一个有一个稳定的用户空间界面。 所以,正如其他人所说的那样,只能依赖覆盖 ,不管是初始部分,还是整个文件,都取决于你的需要。
您可以轻松(部分)覆盖Bash中的初始文件内容,而不会截断文件:
exec {fd}<>"$filename" printf 'New initial contents' >$fd exec {fd}>&-
上面, $fd
是由Bash自动分配的文件描述符, $filename
是目标文件的名称。 Bash在第一行打开一个新的读写文件描述符到目标文件; 这不会截断文件。 第二行覆盖文件的最初部分。 文件中的位置前进,因此可以使用多个命令来覆盖文件中的连续部分。 第三行关闭描述符; 由于每个进程只有有限的可用数量,因此您希望在不再需要它们之后关闭它们,否则长时间运行的脚本可能会用完。
请注意, >
比您预期的要少:
>
和下面的单词,记住重定向。 fork(2)
(或者clone(2)
)来创建一个新的进程。 SOMEVAR=foo yourcommand
),还改变了filedescriptors。 此时,来自cmdline的> yourfile
将以只写模式将stdout filedescriptor(即#1)处的文件open(2)
,将文件截断为零字节 。 A >> yourfile
会产生这样的效果:文件在只写模式和附加模式下在标准输出上运行 。 execv(yourprogram, yourargs)
举一个简单的例子,重定向可以被实现
open(yourfile, O_WRONLY|O_TRUNC);
要么
open(yourfile, O_WRONLY|O_APPEND);
分别。
然后启动的程序将设置正确的环境,并可以愉快地写入fd1。 从这里, 壳不涉及 。 真正的工作不是由shell完成的,而是由操作系统完成的。 由于Unix没有预先模式(并且不可能正确地集成这个特性),所以你可以尝试的所有事情都会以非常糟糕的方式结束。
试着重新考虑你的要求,总是有一个更简单的方法。