Регулярне вираження в bash-скрипті


12

Це мій сценарій башти вперше, тому я, мабуть, робив легку помилку.

В основному, я намагаюся написати сценарій, який отримує групи користувача, і якщо вони знаходяться в певній групі, це буде відповідно до цього. Очевидно, буде більше функціональних можливостей, але немає сенсу будувати, що коли я навіть не можу згенерувати функцію!

Поки що я маю це:

#!/bin/bash

regex="^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"

# example output
groups="username : username usergroup"

echo "$groups" >> /home/jrdn/log

if [[ "$groups" =~ $regex ]]; then
    echo "Match!" >> /home/jrdn/log
else
    echo "No match" >> /home/jrdn/log
fi

Кожне місце, де я спробував цей регулярний вираз, працює. Але у сценарії bash він лише коли-небудь виводить $groups, після чого No match. Тож хтось може сказати мені, що з цим погано?


1
Що змушує вас думати, що з цим щось не так?
манатство

1
@jrdnhannah, потім спробуйте повільно відтворити цільовий регулярний вираз, спочатку збіг, ^([a-zA-Z0-9\-_]+)потім додайте двокрапку і так далі ... ви повинні незабаром дізнатися, де проблема.
петерф

2
Те саме тут з басом 4.2.45. Уникнувши підкреслення, це виправлено. Дивно. @jrdnhannah ви могли б написати це як відповідь і прийняти це будь ласка?
terdon

1
Оскільки я тільки що підписався на Unix SE, від мене потрібно чекати 8 годин, перш ніж відповісти на свій власний. Рада відзначити це як відповідь, якщо хтось ще робить, хоча.
jrdn

4
@terdon bash, ймовірно, просто викликає функції regex libc. Тож це залежить від версії libc, а не від bash версії. Дивіться мою відповідь ... (А може, навіть у послідовності порівняння, яку ви використовуєте)
derobert

Відповіді:


13

Від man 7 regex:

Вираз у дужках - це список символів, укладений у "[]". …

… Щоб включити буквальне «-», зробіть його першим чи останнім символом…. [A] Інші спеціальні символи, включаючи "\", втрачають своє особливе значення в дужці.

Спроба regexp з egrep видає помилку:

$ echo "username : username usergroup" | egrep "^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"
egrep: Invalid range end

Ось більш проста версія, яка також дає помилку:

$ echo 'hi' | egrep '[\-_]'
egrep: Invalid range end

Оскільки \це не особливе, це діапазон, як [a-z]би було. Вам потрібно поставити своє -кінець, як-от [_-]або:

echo "username : username usergroup" | egrep "^([a-zA-Z0-9_-]+ : [a-zA-Z0-9_-]+) (usergroup)$"
username : username usergroup

Це має працювати незалежно від вашої версії libc (в egrep чи bash).

редагувати: Це фактично залежить і від налаштувань вашої мови. Сторінка сторінки попереджає про це:

Діапазони дуже залежать від послідовності послідовності, і переносні програми повинні уникати покладання на них.

Наприклад:

$ echo '\_' | LC_ALL=en_US.UTF8 egrep '[\-_]'
egrep: Invalid range end
$ echo '\_' | LC_ALL=C egrep '[\-_]'
\_

Звичайно, навіть якщо він не помилився, він не робить те, що хочеш:

$ echo '\^_' | LC_ALL=C egrep '^[\-_]+$'
\^_

Це діапазон, який в ASCII, включає в себе \, [, ^, і _.


Цікаво. Моя egrepне дає помилок, просто відповідає їй правильно.
манатура

@manatwork ваша послідовність порівняння, ймовірно, дозволяє діапазон ....
derobert

Я мало знаю про співставлення. Ви маєте в виду це: LC_COLLATE="en_US.UTF-8"?
манатство

@manatwork Я відредагував питання, щоб навести приклад. Зверніть увагу, що у вашій системі це може бути різним, тому що іноді ці послідовності зіставлення (сортування) змінюються.
derobert

1
@manatwork Все гаразд, я майже подав повідомлення про помилку, перш ніж помітив спробу втечі -...
derobert

4

Загальне правило щодо regexps (і будь-яких помилок у більших фрагментах коду): зменшіть його та відновіть його поетапно або використовуйте бісеринг - все, що для вас краще.

У цьому випадку винуватцем виявилося підкреслення - втеча з косою рисою змусила його працювати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.