Escape [в grep

С тех пор как я деактивировал bt_coex, проблема для меня решена. Если я не подключаю мышь слишком быстро после пробуждения из режима ожидания (т.е.: жду, пока установится WiFi), все работает нормально.

4
28.04.2017, 01:43
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.

2
27.01.2020, 20:45

Либо экранируйте его, либо поместите его в класс символов, что-то в этом роде:

grep '\['

grep '[[]'

grep -e "${user//\[/\\\[}"

Синтаксис ${var//c/d} => в переменной оболочки $var заменяем все символы c на d. Теперь в вашем случае c — это [, но так получилось, что [ является особенным в этом синтаксисе (оно делает подстановку), и, следовательно, нам нужно его избежать поставив перед ним обратную косую черту, т. е. \[.

Теперь перейдем к запасной части. Нам нужен \[. Но опять же, и \, и [ являются специальными в этом синтаксисе подстановки параметров ${var//...} и, следовательно, оба должны быть, да вы правильно догадались, косая черта приводя к выражению: \\\[ : "${var//\[/\\\[}"

HTH

10
27.01.2020, 20:45

[ — не единственный символ, который экранируется для регулярных выражений. Все операторы 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 дадут вам информацию для идентификатора пользователя в этом случае Имена пользователей не могут быть числовыми в большинстве систем (это нарушит большинство команд, которые ожидают либо имена пользователей, либо идентификаторы пользователей в качестве аргументов (например, ids выше, ps, найти...))).

5
27.01.2020, 20:45

Теги

Похожие вопросы