탈출 [ 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은 모든 문자 cd. 이제 귀하의 경우에는 cis 가 이 구문에서 특별하기 [때문에 [(글로빙을 수행함) 백슬래시를 접두사로 붙여 이스케이프해야 합니다(예: ) \[.

이제 교체 부품을 살펴보겠습니다. 필요한 것은 \[거기에 있습니다. 하지만 다시 말하지만, 이 매개변수 대체 구문에서는 \및 둘 다 [특별하므로 ${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 래퍼 작성을 건너뛰겠습니다.

관련 정보