gpt4 book ai didi

linux - 如何在 Linux/bash 中使用 && 编辑排队的进程?

转载 作者:太空狗 更新时间:2023-10-29 11:12:17 24 4
gpt4 key购买 nike

假设我有 3 个进程在 Linux/Shell 终端中排队,使用 && 分隔各个进程的命令,如下所示:

<command1> && <command3> && <command4>

现在正在执行 process1 的命令,我想编辑队列:


例如1:我想在 process1 和 process3 之间有另一个 process2。这样更新后的命令队列就变成了:

<command1> && <command2> && <command3> && <command4>

例如2:或者可能会删除一个过程,例如队列中的 process3。这样更新后的命令队列就变成了:

<command1>  && <command4>

有没有办法即时编辑命令队列?即 process1 何时已被执行?

最佳答案

你说的是command listbash(不是队列)中,一旦 shell 解析它,就不能修改它。

从问题中不清楚你是否真的需要队列,或者简单的退出状态测试将为你服务,例如:

#!/bin/bash
if cmd1; then
cmd2
else
if cmd3; then
cmd4
fi
fi

(这将首先运行 cmd1,然后,根据它的成功,运行 cmd2 如果成功,或者尝试运行 cmd3,然后使用 cmd4。最后一个 if block 可以简化为 cmd3 && cmd4。)

但是,如果您真的需要命令队列,则必须自己实现一个。

尝试一:简单数组队列

第一个想法是将队列存储在一个 shell 数组变量中,如下所示:

#!/bin/bash

declare -a queue

clear() { queue=(); }

is_empty() (( ! ${#queue[@]} ))

# insert an item at the beginning
insert() {
queue=("$1" "${queue[@]}")
}

# append an item at the end
push() {
queue=("${queue[@]}" "$1")
}

# remove an item from the beginning
pop() {
queue=("${queue[@]:1}")
}

# return the first item, without popping it
peek() {
echo "${queue[0]}"
}

然后用它来运行这样的命令:

# run commands from the `queue`
run() {
while ! is_empty; do
local cmd=$(peek)
pop
eval "$cmd" || return
done
return 0
}

# run: echo before && sleep 1 && echo after
clear
push 'echo before'
push 'sleep 1'
push 'echo after'
run

但是这种方法的主要问题是您不能真正异步地修改这个队列。您可以在运行之前修改它,或者在 run 循环 中运行时修改它,但这可能不是您所要求的。

您可能会想,为什么我们不能使用 run & 在后台执行命令。好吧,我们可以,但是后台子进程(子 shell )将收到它自己的 queue 变量副本,并且您在生成后所做的修改不会反射(reflect)在 run 子流程。

尝试2:简单文件队列

另一种方法是通过每行存储一个命令来在文件中实现队列。这实际上可行,但我们还需要确保某些互斥机制就位(例如 flock)。

虽然这种方法有效,但我不喜欢每次需要在位置 0 插入命令时重写整个文件的想法。不过,您可以通过在 /上创建文件来将文件保存在内存中dev/shm (ramdisk),但这在 MacOS 上不起作用。

尝试3:Redis队列

前一种方法的逻辑扩展是使用一个实际的共享内存队列,就像 Redis 提供的队列一样。 .

此基于 Redis 的队列的

bash 包装器将是:

#!/bin/bash

redis=(redis-cli --raw)

clear() {
"${redis[@]}" DEL queue &>/dev/null
}

is_empty() (( $("${redis[@]}" LLEN queue) == 0 ))

# insert the item at the beginning
insert() {
"${redis[@]}" LPUSH queue "$1" &>/dev/null
}

# append the item at the end
push() {
"${redis[@]}" RPUSH queue "$1" &>/dev/null
}

# remove the item from the beginning
pop() {
"${redis[@]}" LPOP queue
}

peek() {
"${redis[@]}" LRANGE queue 0 0
}

show() {
"${redis[@]}" LRANGE queue 0 -1
}

您可以运行您的第一个示例(在运行前一个命令时插入),如下所示:

# run commands from the redis queue
run() {
while ! is_empty; do
eval "$(pop)" || return
done
return 0
}

# start with: echo before && sleep 1 && echo after
clear
push 'echo before'
push 'sleep 3'
push 'echo after'

run &

# but then, 1sec after running, modify the queue, insert another command
sleep 1
insert 'echo inserted'

wait

示例输出:

$ ./redis-queue-demo.sh
before
inserted
after

你的例子的解决方案

因此,使用 Redis 方法,您的第一个示例(插入命令)将如下所示:

clear
push 'echo command1; sleep 2'
push 'echo command3'
push 'echo command4'

run &

sleep 1
insert 'echo command2'

wait

输出:

command1
command2
command3
command4

第二个例子(删除命令):

clear
push 'echo command1; sleep 2'
push 'echo command3'
push 'echo command4'

run &

sleep 1
pop >/dev/null

wait

输出:

command1
command4

关于linux - 如何在 Linux/bash 中使用 && 编辑排队的进程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45586533/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com