我想制作具有打开和关闭功能的 shell 脚本,
就像这样
第一次:
echo -e "Activated!"
第二次:
echo -e "Deactivated!"
有没有办法做到这一点?
答案1
这样做意味着您必须保存激活的当前状态。
最简单的方法是为其中一种状态(可能是“开启”或“激活”状态)创建一个文件,并在进入另一种状态(“关闭”或“停用”)时删除该文件。
使用 完成创建空文件touch filename
,并使用 完成测试该文件是否存在if [ -e filename ]; then ...; fi
。删除带有rm filename
.
下面为您提供了通过将变量的值保存到文件来存储该状态下的一些信息的选项。在这种情况下,状态由一个持久文件承载,该文件在每次运行脚本时都会更改(而不仅仅是每次调用脚本时创建或删除的文件)。
假设您正在使用bash
:
#!/bin/bash
statefile=$HOME/.script.state
if [ -f "$statefile" ]; then
. "$statefile"
fi
case $state in
on) state=off ;;
*) state=on
esac
printf 'Current state is "%s"\n' "$state"
declare -p state >"$statefile"
测试:
$ bash script.sh
Current state is "on"
$ bash script.sh
Current state is "off"
$ bash script.sh
Current state is "on"
$ bash script.sh
Current state is "off"
该脚本在每次运行结束时通过 in 保存变量,并通过在开始时获取该文件(如果该文件存在)从state
那里$HOME/.script.state
读取declare -p state
变量。bash
这个文件最终看起来像
declare -- state="off"
declare -p state
这是if $state
is the string的输出off
。
有了/bin/sh
,上面的脚本可以写成
#!/bin/bash
statefile=$HOME/.script.state
if [ -f "$statefile" ]; then
read state <"$statefile"
fi
case $state in
on) state=off ;;
*) state=on
esac
printf 'Current state is "%s"\n' "$state"
printf '%s\n' "$state" >"$statefile"
...只需用 and 替换状态的读取和写入read
,printf
这将仅将状态字符串本身保存在状态文件中。
答案2
如果您希望在每次运行时自动反转状态,您还可以利用“逻辑否定”数字运算,这对于反转值很有用。即0的逻辑非为1,反之亦然。
POSIX shell 能够通过以下方式执行最常见的数字和位运算算术扩展, 和Bash 并不短,还提供数组可以用 0 或 1(以及更多)等整数进行索引。
在实践中:
(
# our persistent file to save state into
file=./state
# array of two states, "off" is the first so that it will be 0, and "on" will be 1
states=(off on)
# import what's been saved in our state file, if present
[ -f "$file" ] && source "$file"
# within the arithmetic expansion syntax,
# we compute new state as the logical negation (the `!` operator) of the current state
state=$(( !(state) ))
printf 'state=%d\n' $state > "$file" # save new state to persistent file
# print current state from the array using the numeric state as index
printf 'currently %s\n' "${states[state]}"
)
在严格的 POSIX shell 中,它有点复杂,因为我们需要解决缺少数组的问题:
(
file=./state
# here we use a simple string instead of an array
states='off on'
[ -f "$file" ] && . "$file" # the `source` command POSIXly is just `.`
state=$(( !(state) ))
printf 'state=%d\n' $state > "$file"
# here we use the `cut` tool to select the piece of string based on numeric state
echo -n 'currently '; printf '%s\n' "$states" | cut -d ' ' -f $((state+1))
)