Bash 在循环内设置全局变量并保留其值——或者过程替换虚拟变量

发布于 2024-12-29 01:47:28 字数 1748 浏览 1 评论 0原文

我是一名 C/C++ 程序员,总体来说相当愚蠢(或者至少 bash 做事的方式让我感到困惑)。我无法理解流程替换。

我需要定义一个全局布尔值,将其设置在循环中的某个位置,并在全局范围内使用它。有人可以用最简单的方式解释如何调整下面的代码以允许我实现我的用例,足够简单,这样我明天就不必再次扭曲我的大脑来尝试掌握流程替换。

# DEFINE HERE

for i in `seq 0 ${DAEMON_COUNT}`;
do
        if [ ! -d "data$i" ]; then
# SET HERE
                echo "data$i does not exist. Creating...";
                mkdir data$i
        fi
done

# TEST AND USE HERE

老实说,我认为 bash 无法胜任这项任务......下一个块看起来像这样。

echo "-------------------------------------------------------------------------------"
echo "checking the state of potentially running daemons"
for i in `seq 0 ${DAEMON_COUNT}`;
do
        if [ ! -e "data$i/mongod.lock" ] ; then
                echo "[no lock file] mongod process $i does not exist"
        else
                echo "[lock file exists] process $i lock file exists "
                I_PID=`cat data$i/mongod.lock`

                if [ ! ${I_PID} ]; then
                        echo "    [GOOD] lock pid empty"
                elif [ "`ps -p ${I_PID} | grep ${I_PID}`" ]; then
                        echo "    [GOOD] data1 pid: ${I_PID} running"
                else 
                        echo "[PROBABLY FATAL] data1 pid: ${I_PID} not running."
                fi 
        fi
done
echo "-------------------------------------------------------------------------------"

我现在需要的是一个全局结构数组,以便我可以循环它们并采取条件操作来正确初始化我的守护进程:/。

可能只使用 libc 并在 lua 中执行此操作,我犹豫的唯一原因是必须安装岩石,我不喜欢临时代码存储库将他们想要的任何东西吐到我的机器上:D

I'm a C/C++ programmer and quite stupid in general (or at least the way bash does things it makes me feel confused). I can't wrap my head around process substitution.

I need to define a global boolean, set it somewhere in a loop, and make use of it in global scope. Could someone please explain in the simplest way possible how to adapt the code below to allow me to achieve my use case, simple enough so that I don't have to contort my brain again tomorrow to try and grasp process substitution .

# DEFINE HERE

for i in `seq 0 ${DAEMON_COUNT}`;
do
        if [ ! -d "data$i" ]; then
# SET HERE
                echo "data$i does not exist. Creating...";
                mkdir data$i
        fi
done

# TEST AND USE HERE

to be honest, I don't think bash is up to the task.... the next block looks like this.

echo "-------------------------------------------------------------------------------"
echo "checking the state of potentially running daemons"
for i in `seq 0 ${DAEMON_COUNT}`;
do
        if [ ! -e "data$i/mongod.lock" ] ; then
                echo "[no lock file] mongod process $i does not exist"
        else
                echo "[lock file exists] process $i lock file exists "
                I_PID=`cat data$i/mongod.lock`

                if [ ! ${I_PID} ]; then
                        echo "    [GOOD] lock pid empty"
                elif [ "`ps -p ${I_PID} | grep ${I_PID}`" ]; then
                        echo "    [GOOD] data1 pid: ${I_PID} running"
                else 
                        echo "[PROBABLY FATAL] data1 pid: ${I_PID} not running."
                fi 
        fi
done
echo "-------------------------------------------------------------------------------"

What I now need is a global array of structs so that I can loop over them and take conditional action to initialize my daemons correctly :/.

Might just use libc and do this stuff in lua, the only reason I hold back is having to install rocks, I don't like ad-hoc code repositories vomiting whatever they want onto my machine :D

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

扛起拖把扫天下 2025-01-05 01:47:29

使用 ksh。它处理 | 的右侧不是作为子 shell,而是作为当前 shell。

#!/bin/bash
x=1; echo -e "1\n2\n3" | while read n; do x=$n; done; echo x=$x

x=1

#!/bin/ksh
x=1; echo -e "1\n2\n3" | while read n; do x=$n; done; echo x=$x

x=3

ksh 可安装在 Ubuntu 中。

Use ksh. It processes the right side of | not as a subshell but a current shell.

#!/bin/bash
x=1; echo -e "1\n2\n3" | while read n; do x=$n; done; echo x=$x

x=1

#!/bin/ksh
x=1; echo -e "1\n2\n3" | while read n; do x=$n; done; echo x=$x

x=3

ksh is installable in Ubuntu.

小清晰的声音 2025-01-05 01:47:28

需要理解的重要一点是:子进程天生就有自己的环境,不能影响其父进程的变量。如果在子进程中设置变量,则父进程中的变量值不会受到影响。这实际上是两个不同的变量,只是碰巧具有相同的名称。

第二件需要理解的事情是 bash 何时作为子进程运行命令。有两种情况与该问题相关:

  1. 通过管道 | 连接的每个进程都是当前 shell 的子进程。
  2. 运行带有重定向的单个内置命令(例如 <)不会生成子进程。

下面是一个简单的会话,它演示了这些想法:

$ somevar=initial
$ echo test1 | read somevar
$ echo $somevar
initial
$ read somevar < <(echo test2)
$ echo $somevar
test2

第一个 read 是一个子进程,因此主 shell 中的 somevar 不会改变。第二个 read 由主 shell 本身执行,因此 somevar 被更新。

这意味着您的代码将按您的预期工作,除非您在 for 循环之前或之后添加管道,即这将按您希望的方式工作:

# DEFINE HERE
SOMEVAR=0
DAEMON_COUNT=10

for i in `seq 0 ${DAEMON_COUNT}`;
do
        if [ ! -d "data$i" ]; then
# SET HERE
                SOMEVAR=10
                echo "data$i does not exist. Creating...";
                mkdir data$i
        fi
done

# TEST AND USE HERE
echo ${SOMEVAR}     # This displays 10

The important thing to understand is this: child process is born with its own environment and cannot affect the variables of its parent. If you set a variable in a child process, then the value of the variable in the parent is not affected. These are actually two different variables which just happen to have the same name.

The second thing to understand is when bash runs a command as a child process. There are two cases relevant to the question:

  1. Each process connected by a pipe | is a child of the current shell.
  2. Running a single builtin command with a redirection (e.g. <) will not spawn a child process.

Here is a simple session which demonstrates these ideas:

$ somevar=initial
$ echo test1 | read somevar
$ echo $somevar
initial
$ read somevar < <(echo test2)
$ echo $somevar
test2

The first read is a child process and therefore somevar in the main shell does not change. The second read is executed by the main shell itself and hence somevar is updated.

This means that your code will work as you expect unless you add a pipe in front of or after the for loop, i.e. this works as you want it to:

# DEFINE HERE
SOMEVAR=0
DAEMON_COUNT=10

for i in `seq 0 ${DAEMON_COUNT}`;
do
        if [ ! -d "data$i" ]; then
# SET HERE
                SOMEVAR=10
                echo "data$i does not exist. Creating...";
                mkdir data$i
        fi
done

# TEST AND USE HERE
echo ${SOMEVAR}     # This displays 10
套路撩心 2025-01-05 01:47:28

我可能误解了但是...

bool=false;

for i in `seq 0 ${DAEMON_COUNT}`;
do
    if [ ! -d "data$i" ]; then
            bool=true;
            echo "data$i does not exist. Creating...";
            mkdir data$i
    fi
done

if [ $bool = true ]; then 
    ... 
fi

这是你想要的吗?

I might have misundestood but...

bool=false;

for i in `seq 0 ${DAEMON_COUNT}`;
do
    if [ ! -d "data$i" ]; then
            bool=true;
            echo "data$i does not exist. Creating...";
            mkdir data$i
    fi
done

if [ $bool = true ]; then 
    ... 
fi

Is this what you want?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文