创建一个与 bash 中的文件内容同步的变量

create a variable that is in sync with a files content in bash

在 bash 中,我想读入一个与文件内容不断同步的变量。

我该如何完成?

echo "test" > /tmp/test
value=$(</tmp/test)

echo $value
test

echo "test2" > /tmp/test
echo $value
test    # Id 'like this to return test2

正如@Fravadona 评论的那样,不可能。

使用函数是一种解决方法:

value() { cat /tmp/test; }

echo "test" > /tmp/test
echo $(value)   # => test

echo "test2" > /tmp/test
echo $(value)   # => test2

有一种方法可以做你想做的事情。基本思想是 运行 一个后台进程来监视文件的更改并在更改发生时向您的程序发送信号。程序中的信号处理程序可以在收到信号时更新变量值。

这段 Shellcheck-clean 代码演示了这个想法:

#! /bin/bash -p

# Turn on monitor mode (job control).
# (This causes background processes to run in separate process groups, making
# it easy to kill a background process and all processes created by it.)
set -o monitor

# Send a SIGUSR1 signal to the given PID () whenever the contents of the
# given file () change
function send_sigusr1_on_file_change
{
    local -r pid=
    local -r file=

    inotifywait -m -q -e modify -- "$file" \
        |   while read -r _; do
                kill -USR1 "$pid"
            done

    return 0
}

# Initialize the test file and the 'value' variable to empty
: >/tmp/test
value=''

# Update 'value' with the contents of '/tmp/test' whenever a
# SIGUSR1 signal is received.
trap 'value=$(< /tmp/test)' SIGUSR1

# Run a background process to scan for changes in '/tmp/test' and send
# SIGUSR1 signals to this process ($$) when they occur.
send_sigusr1_on_file_change "$$" /tmp/test &
signaller_pid=$!

# Set a trap to kill the background process when this program exits.
# (Negating the PID causes all processes in the process group associated with
# the background process to be killed.  This is to prevent subprocesses
# created by the background process (e.g. 'inotifywait') from continuing to
# run after it is killed.)
trap 'kill -- "-$signaller_pid"' EXIT

# Wait for the signaller loop to start signalling changes
sleep 1

echo 'test' >/tmp/test
sleep 0.01  # Wait for the change to the file to be detected and signalled

printf '%s\n' "$value"

echo 'test2' >/tmp/test
sleep 0.01  # Wait for the change to the file to be detected and signalled

printf '%s\n' "$value"

在我的 Linux 测试系统上,程序始终输出:

test
test2
  • 因为文件更改和变量更新之间有一个小的延迟,我不得不添加对 sleep 的调用以使其可靠地工作。这对你来说可能是个问题。
  • 我已经使用 inotifywait 有效地扫描文件中的更改。您可能需要使用替代方案,具体取决于系统上可用的或可以安装的内容。您也可以使用轮询循环,但这会更 resource-hungry,并且可能导致更新变量的延迟时间更长。
  • 请参阅对 Why is printf better than echo? 的公认且优秀的回答,以了解我为何使用 printf 而不是 echo 来打印变量值的解释。 (echo 可以打印(一些)固定字符串。)