![grep 中的转义符 [](https://linux22.com/image/110451/grep%20%E4%B8%AD%E7%9A%84%E8%BD%AC%E4%B9%89%E7%AC%A6%20%5B.png)
我从标准输入读取字符串,我想显示与字符串匹配的用户。问题是,如果用户输入字符“[”或包含它的字符串。
grep -F
不起作用,因为该行必须以字符串开头(^ - 这是带有 -F 的简单字符)。另外,getent $user
这也不好,因为我只需要用户名而不是 ID。
if [[ "$user" == *"["* ]]; then
echo -e "Invalid username.\n"
continue
fi
if ! getent passwd | grep "^$user:"; then
echo -e "Invalid username.\n"
continue
fi
这是“[”的解决方法,还有其他方法吗?
awk
最有可能完成这项工作,但我对此还不了解,我对 grep 感兴趣。
答案1
要么转义它,要么将它放入字符类中,大致如下:
grep '\['
grep '[[]'
grep -e "${user//\[/\\\[}"
${var//c/d}
shell 变量中的语法=>$var
我们将所有字符替换c
为d
。现在,在您的情况下,但c
它[
恰好[
在这种语法中很特殊(它确实进行通配),因此我们需要通过在其前面加上反斜杠来转义它,即\[
。
现在谈到替换部件,我们需要的是\[
其中的一个。但同样,在参数替换的语法中,\
和都是特殊的,因此,是的,你猜对了,两者都需要加反斜杠,导致表达式: : [
${var//...}
\\\[
"${var//\[/\\\[}"
华泰
答案2
[
不是正则表达式唯一需要转义的字符。所有 RE 运算符都包括.
用户名中常见的运算符(r.ot
例如,正则表达式匹配root
)。
此外,您的方法 ( getent passwd | grep "^$user:"
) 也是无效的,因为它不会标记root:0
为无效。
在这里,最好使用awk
:
user_valid() {
getent passwd |
U="$1" awk -F: '$1 == ENVIRON["U"] {found = 1; exit}
END {exit(1 - found)}'
}
现在,并非所有用户数据库都允许这样的枚举。
$ getent passwd | grep stephane
$ id -u stephane
10631
$ getent passwd stephane
stephane:*:10631:10631:Stephane Chazelas:/export/./home/stephane:/bin/zsh
就我而言,该用户位于 LDAP 数据库中。枚举已禁用(可能有数千个用户),但我仍然可以单独查询/解析用户。
因此,在这里,为了验证用户,最好直接查询该用户的用户数据库。例如,使用以下id
命令(与 相反的标准命令getent
):
user_valid() {
case $1 in
(*[!0-9]*) id -u -- "$1" > /dev/null 2>&1;;
(*) false;;
esac
}
(我们单独处理全数字用户,因为id
在这种情况下,某些实现会为您提供用户 ID 的信息。在大多数系统中,用户名不能是数字(这会破坏大多数需要用户名或用户名的命令) ids 作为参数(如id
上面的那些,ps
... find
)))。
答案3
转义特殊字符有点麻烦。相反,您可以先从 的输出中选择用户名字段getent
,然后与剩余的完整行进行匹配:
LC_ALL=C
if ! [[ $user =~ ^[A-Za-z0-9._][A-Za-z._-]*$ ]] ; then
echo "Username is invalid"
continue
fi
getent passwd | cut -d: -f1 | grep -xF -e "$user"
-F
对于固定字符串,-x
对于全行匹配。
如果您没有用户名仅由数字组成的用户,您可以使用getent
:
LC_ALL=C
if ! [[ $user =~ ^[A-Za-z0-9._][A-Za-z._-]*$ ]] ; then
echo "Username is invalid"
continue
elif [[ $user =~ ^[0-9]+$ ]] ; then
echo "Cannot handle username of digits only, sorry :("
continue
fi
if ! getent -- passwd "$user" > /dev/null ; then
echo "$user doesn't exist"
continue
fi
或者,为了避免出现问题getent
或其他人假设一串数字必须是 UID 而不是用户名,我们应该调用getpwnam()
手动。除了底层getpwnam()
实现的作用之外,这不会对用户名做出其他假设。
export user
if ! perl -e 'exit !defined getpwnam($ENV{user})' ; then
echo "$user doesn't exist"
fi
我将跳过编写相应的 C 包装器。