我是 shell 脚本新手,我想知道是否有比我想出的更好的解决方案:
我想检查用户是否在列表中,如果是,则脚本应使用 exit_program 函数终止:
$USER 被定义为登录系统的人
我的解决方案(有效)是:
$IGNORE_USER="USER1 USER2 USER3"
if [ ! -z "$IGNORE_USER" ]; then
for usr in $IGNORE_USER
do
if $USER = $usr; then
exit_program "bye bye"
fi
done
fi
答案1
该脚本的作用是不是工作。
第一行存在语法错误,因为对 的赋值IGNORE_USER
不应使用 取消引用变量$
。您的语句中还有另一个语法错误if
。用于[ "string1" = "string2" ]
比较字符串。
您的代码依赖于使用$IGNORE_USER
不带引号的。这将字符串按空格分割,这就是您想要做的。在最一般的情况下,这是不是不过,您想要做什么,因为列表中的项目很可能包含应保留的空白字符。如果使用不带引号的字符串,shell 还会对字符串中的值执行文件名生成(通配符)。
当您处理单独的项目(用户名)时,最好使用数组。每当您想将单独的项目视为分离项目,不要将它们放在单个字符串中。这样做可能会导致难以区分一件物品和另一件物品。
建议:
ignore=( 'user1' 'user2' 'user3' )
for u in "${ignore[@]}"; do
if [ "$USER" = "$u" ]; then
exit_program 'bye bye'
fi
done
这假设exit_program
负责退出程序。如果没有,请exit
在调用后添加exit_program
。无需测试ignore
数组是否为空,因为如果为空,循环将不会运行单次迭代。
在上面的代码中,"${ignore[@]}"
(注意双引号)将扩展到用户名列表,每个用户名都单独引用并防止进一步的分词和文件名生成。
有关的:
对于不特定于 的版本bash
,但可以在任何类似 POSIX 的 shell 中运行:
set -- 'user1' 'user2' 'user3'
for u do
if [ "$USER" = "$u" ]; then
exit_program 'bye bye'
fi
done
这使用位置参数列表作为要忽略的用户名列表,而不是数组。
答案2
grep解决方案
使用 , 的“-w”功能grep
来匹配单词。我敢说它不适用于较旧的grep
实现,例如 Solaris、AIX 等。
echo $IGNORE_USER | grep -qw $USER && exit_program 'bye bye'
bash内部解决方案
完全使用 bash,不要依赖grep
.
bash
不允许构造=~ regex
除非你shopt -s compat31
先运行。因此,通过使用=~ $(echo regex)
我们可以克服这个问题。我们在这个例子中使用双引号,以便$USER
扩展,这样做时我们需要转义 to \b
be \\b
。
[[ $IGNORE_USER =~ $(echo "\\b$USER\\b") ]] && exit_program 'bye bye'