如何在Linux中向Bash添加运算符?

时间:2012-08-14 18:05:59

标签: c linux bash

我想添加一个运算符(例如^>)来处理prepend而不是append(>>)。我是否需要修改Bash源或是否有更简单的方法(插件等)?

6 个答案:

答案 0 :(得分:3)

首先,你需要修改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期间其他内容会写入磁盘并填满,那么您最终会得到不完整的文件。

说实话,我不会亲自使用它,但如果需要,可以在外部处理符号链接和重置权限。

答案 1 :(得分:2)

^是一个糟糕的角色选择,因为它已在history substitution中使用。


要向shell语法添加新的重定向类型,请从parse.y开始。将其声明为新的%token以便可以使用它,将其添加到STRING_INT_ALIST other_token_alist[]以便它可以出现在输出中(例如错误消息),更新解析器中的redirection规则,并在遇到相应的字符时更新词法分析器以发出此标记。

command.h包含enum r_instruction个重定向类型,需要进行扩展。在switch处理重定向指令的make_redirection中有一个巨大的make_cmd.c语句,实际的重定向由整个redir.c中的函数执行。在其余的源代码中分散了各种用于打印,复制和销毁管道的功能,这些功能也可能需要更新。

这就是全部! Bash并不是 复杂。


这里没有讨论如何实现预先重定向,这很难,因为UNIX文件API只提供附加和覆盖。预先添加到文件的唯一方法是完全重写它,(正如其他答案所提到的)比任何现有的shell重定向要复杂得多。

答案 2 :(得分:1)

可能很难添加运算符,但是函数可能就足够了吗?

function prepend { tmp=`tempfile`; cp $1 $tmp; cat - $tmp > $1; rm $tmp; }

使用示例:

echo foobar | prepend file.txt

将文本“foobar”添加到file.txt。

答案 3 :(得分:0)

我认为bash的插件架构(通过'enable'内置命令加载共享对象)仅限于提供额外的内置命令。重定向运算符是运行简单命令的语法的一部分,因此我认为您需要修改解析器以识别和处理新的^>运算符。

答案 4 :(得分:0)

大多数Linux文件系统不支持预先添加。事实上,我不知道任何一个拥有稳定用户空间接口的人。因此,正如其他人已经说过的那样,您只能依靠覆盖,只需要初始部分或整个文件,具体取决于您的需求。

您可以轻松(部分)覆盖Bash中的初始文件内容,而不会截断文件:

    exec {fd}<>"$filename"
    printf 'New initial contents' >$fd
    exec {fd}>&-

上面,$fd是Bash自动分配的文件描述符,$filename是目标文件的名称。 Bash在第一行打开一个新的读写文件描述符到目标文件;这样做截断文件。第二行会覆盖文件的初始部分。文件中的位置前进,因此您可以使用多个命令覆盖文件中的连续部分。第三行关闭描述符;由于每个进程只有有限的可用数量,因此您希望在不再需要它们之后关闭它们,或者长时间运行的脚本可能用完。

答案 5 :(得分:0)

请注意,>的效果低于预期:

  1. 从命令行中删除>和以下单词,记住重定向。
  2. 处理命令行并启动命令后,调用fork(2)(或clone(2)),以创建新流程。
  3. 根据命令修改新进程。包括修改后的环境变量(SOMEVAR=foo yourcommand)等内容,还包括更改的文件描述符。此时,cmdline中的> yourfile将使文件在stdout filedescriptor(即#1)处以只写模式截断时生成open(2)文件为零字节>> yourfile会导致文件在stdout中以只写模式和追加模式进行选择。
  4. (现在才启动该计划,例如execv(yourprogram, yourargs)
  5. 对于一个简单的例子,重定向可以像

    一样实现
    open(yourfile, O_WRONLY|O_TRUNC);
    

    open(yourfile, O_WRONLY|O_APPEND);
    

    分别

    然后启动的程序将设置正确的环境,并且可以愉快地写入fd1。从这里开始,不涉及shell 。真正的工作不是由shell完成的,而是由操作系统完成的。由于Unix没有前置模式(并且无法正确集成该功能),所以你可以尝试的一切都会陷入非常糟糕的黑客行为。

    尝试重新考虑您的要求,总是更简单的方法。