grepで[をエスケープする

grepで[をエスケープする

stdin から文字列を読み取り、文字列に一致するユーザーを表示したいと考えています。問題は、ユーザーが文字 '['、またはそれを含む文字列を入力した場合です。

grep -F行は文字列 (^ - は -F の単純な文字) で始まる必要があるため、機能しません。また、getent $userID ではなくユーザー名のみが必要なので、適切ではありません。

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}シェル変数内の構文=> では$var、すべての文字cが に置き換えられますd。さて、あなたの場合、 はcですが[、たまたま[この構文では が特殊であるため (グロブを行う)、 のように、前にバックスラッシュを付けてエスケープする必要があります\[

さて、置換部分ですが、\[ここで必要なのは です。しかし、ここでも と は両方とも\このパラメータ置換[構文では特別なので${var//...}、両方とも、そうです、お察しのとおり、バックスラッシュを付けて次の式にする必要があります。\\\[: "${var//\[/\\\[}"

HTH

答え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 の情報を提供するためです。ほとんどのシステムでは、ユーザー名を数値にすることはできません (そうすると、ユーザー名またはユーザー ID のいずれかを引数として期待するほとんどのコマンドが機能しなくなります (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 ラッパーの記述は省略します。

関連情報