grepのエスケープ文字[

grepのエスケープ文字[

標準入力から文字列を読み取っていますが、その文字列に一致するユーザーを表示したいと思います。問題は、ユーザーが「[」文字またはそれを含む文字列を入力した場合です。

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すべての文字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を提供するため、すべての数値ユーザーを個別に処理します。ほとんどのシステムでは、ユーザー名を数値にすることはできません(これにより、ユーザー名またはユーザー名コマンドを必要とするほとんどのシステムがハングします)。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ラッパーの作成をスキップします。

関連情報