web-dev-qa-db-ja.com

エスケープ[grep内

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

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に興味があります。

4
Tigrex

[は、正規表現でエスケープする唯一の文字ではありません。すべてのRE演算子には、ユーザー名で一般的な.が含まれています(たとえば、正規表現はrootと一致するため、r.ot)。

また、あなたのアプローチ(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を期待します(上記のids、psfind...)のように)。

5

特殊文字のエスケープはちょっと面倒です。代わりに、最初に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
_

または、数字の文字列がユーザー名ではなくUIDでなければならないというgetentなどの問題を回避するには、手動で getpwnam() を呼び出す必要があります。これは、基礎となるgetpwnam()実装が行うこと以外に、ユーザー名が何であるかについて他の仮定をしません。

_export user
if ! Perl -e 'exit !defined getpwnam($ENV{user})' ; then 
    echo "$user doesn't exist"
fi
_

対応するCラッパーの作成はスキップします。

2
ilkkachu