Чи може grep повернути true / false або існують альтернативні методи


130

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

grep ^$1 schemas.txt

Я відчуваю, що це має бути набагато простіше, ніж я це роблю.

Я отримую помилку "занадто багато аргументів" у ifзаяві. Я позбувся місця між, grep -qа потім очікував помилку бінарного оператора.

if [ grep -q ^$1 schemas.txt ]
then
        echo "Schema already exists. Please try again"
        exit 1
else
        echo "$@" >> schemas.txt
fi

1
Втратите []і воно спрацює. Хоча ви, мабуть, хочете процитувати свій зразок:if grep -q "^$1" schemas.txt; then …
derobert

рішення в одному рядку за допомогою функції "Групового командування" Баша: stackoverflow.com/questions/6550484/…
Тревор Бойд Сміт

Відповіді:


186

grepповертає інший код виходу, якщо він знайшов щось (нуль) порівняно, якщо він нічого не знайшов (ненульовий). У ifзаяві нульовий код виведення відображається на "true", а ненульовий код виходу відображається на false. Крім того, grep має -qаргумент не виводити відповідний текст (а лише повертати код статусу виходу)

Отже, ви можете використовувати grep так:

if grep -q PATTERN file.txt; then
    echo found
else
    echo not found
fi

Як швидка примітка, коли ви робите щось на кшталт if [ -z "$var" ]…, виявляється, що [це насправді команда, яку ви виконуєте, як і grep. У моїй системі це /usr/bin/[. (Ну, технічно, ваша оболонка, ймовірно, має вбудований, але це оптимізація. Він поводиться так, ніби це команда). Це працює так само, [повертає нульовий код виходу для істинного, ненульовий код виходу - для хибного. ( testте саме, що [, крім закриття ])


Чому оператору if не потрібні дужки? У мене це працює без, але не розумію, чому. Чи можу я все-таки це гніздо без дужок?
Лорен

@Lauren Ви пропустили швидку записку? [не є частиною синтаксису if, це (концептуально) команда, яку ви виконуєте, як і grep
derobert

2
@Lauren Ви не використовуєте grep всередині [, ви використовуєте те чи інше, залежно від того, який стан ви хочете перевірити. (Ви можете використовувати будь-яку команду всередині if, btw, якщо просто перевіряє код виходу.)… Ну, я думаю, ви, мабуть, могли придумати причину використання grep всередині [, але це був би досить складний сценарій, і його не нормальна річ.
derobert

3
FYI, бігати ls -l /usr/bin/\[і man [бачити , що [це програма , як і будь-який інший, він просто виглядає як синтаксичний елемент - це повинно зробити це очевидним і легше зрозуміти. (для зручності [також вбудований в bash, dash та інші - але це все-таки команда). також спробуйте type -all [в баш.
cas

1
@AlexanderCska, якщо ви хочете, щоб grep надрукував відповідні лінії (наприклад, щоб передати їх кудись), а потім опустіть -qцей параметр, повідомляє grep бути тихим (не друкувати відповідні рядки).
дероберт

47

Ще один простий спосіб - це використовувати grep -c.

Це виводить (не повертається як код виходу), кількість рядків, які відповідають шаблону, так 0, якщо немає відповідності, або 1 або більше, якщо є збіг.

Отже, якщо ви хочете перевірити, чи узор відповідає 3 і більше разів, ви зробите:

if [ "$(grep -c "^$1" schemas.txt)" -ge 3 ]; then
  ...

17
Точніше, це буде вихід 1 , якщо знайдений тільки один раз. Для виведення 1, незалежно від кількості знайдених відповідностей, використовуйте grep -cim1натомість.
манатура

Цей метод також може бути використаний для розмежування помилки grep та grep "шаблону, знайденого 0 разів". (хоча не з точним, якщо заява використовується, я думаю, потрібна змінна)
Еван Бенн

3

Я знаю, що спізнююсь на це, але люблю цю коротку версію:

grep -q ^$1 schemas.txt && echo "Schema already exists. Please try again" || echo "$@" >> schemas.txt

0

Якщо ми хочемо зловити перше слово файлу, нам потрібно додати -zwgrep

if grep -qzw "^$1" file
then 
   ... 
else 
   ... 
fi

Без цього -zми не отримаємо першого слова рядка. Без -wнас дістають часткові слова.


-2

Якщо ви хочете використовувати його з квадратними дужками, ви можете виконати наведене нижче

if [ `grep -q PATTERN file.txt` ]; then
    echo found
else
    echo not found

Ця логіка працює для всіх команд. Просто розмістіть команди всередині зворотного вибору (кнопка вгорі вкладка або вниз від кнопки Esc або зліва від 1 кнопки)


1
Вам потрібно буде навести цитату `grep -q PATTERN file.txt`, інакше застосовується оператор split + glob і це спричинить проблеми для будь-якого виводу, що містить символи $IFSабо символи підстановки. Загалом, [ "`cmd`" ]повернеться true, якщо cmdвиводить принаймні один не порожній рядок у stdout (з потенційними проблемами, якщо він виводить байти NUL). Це означає, що оболонці доведеться зберігати весь вихід у пам'яті та чекати, коли він закінчиться. Використання if cmd | grep -q .натомість може бути кращим у цьому плані.
Стефан Шазелас

Ця команда взагалі не мала б сенсу. Мета -qкомутатора - придушити grep вихід. Ви говорите: Перевірте наявність PATTERN у file.txt, пригнічіть будь-який вихід, а потім встановіть статус повернення відповідно до того, чи було знайдено PATTERN. Потім, ігноруйте статус повернення, візьміть командний висновок (який ми змусили бути порожнім), застосуйте розділення слів та розширення файлу glob (у результаті чого аргументів немає взагалі), а потім запустіть команду [(aka test) точно з одним аргументом - а саме , ]- і тоді, оскільки це призведе до помилки, відлуння "не знайдено". @ StéphaneChazelas, я щось пропустив?
Wildcard

1
@Wildcard, ти маєш рацію, я, мабуть, не помітив -q. Цей коментар мав би сенс [ `grep PATTERN file.txt ` ], але, як натякає в коментарі, [ "`grep -n PATTERN file.txt`" ]було б краще, якщо PATTERN може відповідати лише порожнім рядкам. Хоча тут, звичайно, це if grep -q PATTERN file.txtти хочеш.
Стефан Хазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.