使用 awk 和 truncate 写入同一个文件

Writing to the same file with awk and truncate

我的系统是 Arch Linux,我的 window 管理器是 DWM。我使用 dash 作为我的 shell 解释器。

我已经为我的计时器编写了这个扩展 shell 脚本。


xev -root |
    awk -F'[ )]+' '/^KeyPress/ { a[NR+2] }
            NR in a {
                if ( == "Return") {
                    exit 0;
                } else if ( == "BackSpace") {
                    system("truncate -s-1 timer.txt");
                } else if (length() == 1) {
                    printf "%s", ;
                    fflush(stdout);
                }            
                system("pkill -RTMIN+3 dwmblocks");
            }' | tee timer.txt

计时器本身位于 dwmblocks 状态栏中。我想先命名我的计时器,然后让它开始。不过我觉得没那么重要。

此脚本的用途 - 我想将字符输入到 DWM 的根 window 中,并让它们立即出现在我的状态栏中。因此,xev 生成按键信息,然后 awk 获取该信息,找到确切的键(从 xev 输出)和检查。如果键是“Return”,awk 退出(工作完成)。如果键是“BackSpace”,awk 会从系统调用 truncate。如果它是一个常规字符键,那么 awk 将它输出到 timer.txt with tee (我可以使用 "> timer.txt" 我想也是,但我想在我的终端中查看输出以进行调试。

在每次相关按键(单个字符)之后,我都会刷新标准输出。在所有这一切之后,我终于调用了 pkill 以便 dwmblocks 知道它应该更新。 (dwmblocks 对文件进行 cat 操作)

好的,“Return”和字符输入工作正常。但是“退格键”有问题。我读过一点(我会说我仍然是一个 Unix 新手,尽管我已经使用 Linux 两年了)并且我发现从不同的进程写入同一个文件是个坏消息。仍然。能以某种方式完成吗?事实是 truncate 只在 awk 时写入文件,而不是,所以,也许,这没什么大不了的?

这个确切的脚本昨天早些时候工作,但现在不工作了。起初,我尝试使用 sed 而不是 truncate 并且 truncate 似乎让我从 timer.txt 中删除字符,但现在 truncate 似乎也不再起作用了。好吧,它有点管用。我可以输入我的字符,然后我可以删除它们。 但是。 按退格键后,我无法再输入任何字符。如果我尝试输入字符,退格键也会停止工作。

是的。我有几个问题。首先-到底是什么问题?正如我所说,它曾经有效,但现在无效。我是否陷入了此脚本中的未定义行为?

其次 - 这是否可以完成 - 意思是 - 我可以以某种方式从同一个文件中写入和删除。也许使用其他工具,而不是 awk?

提前致谢。

这可能不是答案,但评论太多了。我不知道你提到的大多数工具的细节,我也不太明白你想做什么,但是:

A shell 是一种用于操作文件和进程以及安排对其他工具的调用的工具。 awk 是一种操作文本的工具。您正在尝试像 shell 一样使用 awk - 您让它对 truncatepkill 的调用进行排序,并调用系统在您每次要执行时生成一个 subshell的任何一方。例如,你应该做的只是:

shell { truncate }

但你实际做的是:

shell { awk { system { shell { truncate } } } }

你能把这个角色从 awk 中拿走,并把它还给你的 shell 吗?它应该使您的整个脚本更简单,至少在概念上如此,并且可能更健壮。

也许尝试这样的事情(未经测试):

#!/usr/bin/env bash

while IFS= read -r str; do
    case $str in
        Return ) exit 0 ;;
        BackSpace ) truncate -s-1 timer.txt ;;
        ? ) printf "%s" "$str" | tee -a timer.txt ;;
    esac
    pkill -RTMIN+3 dwmblocks
done < <(
    xev -root |
    awk -F'[ )]+' '/^KeyPress/{a[NR+2]} NR in a{print ; fflush()}'
)

我将写入移动到循环内的 timer.txt 以确保 tee 在截断它时不会尝试写入它 - 可能 没有必要。