grep 中的轉義符 [

grep 中的轉義符 [

我從標準輸入讀取字串,我想顯示與字串匹配的用戶。問題是,如果使用者輸入字元“[”或包含它的字串。

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我們將所有字元替換cd。現在,在您的情況下,但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 包裝器。

相關內容