Использование регулярных выражений в скрипте оболочки - PullRequest
24 голосов
/ 28 октября 2009

Как правильно проанализировать строку с помощью регулярных выражений в сценарии оболочки linux? Я написал следующий скрипт для печати моего представителя SO на консоли, используя curl и sed (не только потому, что я сумасшедший - я пытаюсь изучить некоторые сценарии оболочки и регулярное выражение перед переключением на linux).

json=$(curl -s http://stackoverflow.com/users/flair/165297.json)
echo $json | sed 's/.*"reputation":"\([0-9,]\{1,\}\)".*/\1/' | sed s/,//

Но почему-то я чувствую, что sed не подходит для использования здесь. Я слышал, что grep это все о регулярных выражениях, и немного изучил его. Но, очевидно, он печатает всю строку всякий раз, когда найдено совпадение - я пытаюсь извлечь число из одной строки текста. Вот уменьшенная версия строки, над которой я работаю (возвращается curl).

{"displayName": "Amarghosh", "Reputation": "2,737", "badgeHtml": "\ u003cspan title = \" 1 серебряный значок \ "\ u003e \ u003cspan class = \" badge2 \ "\ u003e ● \ u003c / span \ u003e \ u003cspan class = \ "badgecount \" \ u003e1 \ u003c / span \ u003e \ u003c / span \ u003e "}

Я думаю, мои вопросы:

  • Как правильно проанализировать строку с помощью регулярных выражений в сценарии оболочки linux?
  • sed Правильно ли здесь использовать?
  • Можно ли это сделать с помощью grep?
  • Есть ли какая-нибудь другая команда, которая более проста / уместна?

Ответы [ 11 ]

12 голосов
/ 28 октября 2009

Команда grep выберет нужную строку (и) из многих, но не будет напрямую манипулировать этой строкой. Для этого вы используете sed в конвейере:

someCommand | grep 'Amarghosh' | sed -e 's/foo/bar/g'

В качестве альтернативы можно использовать awk (или perl, если доступно). На мой взгляд, это гораздо более мощный инструмент обработки текста, чем sed.

someCommand | awk '/Amarghosh/ { do something }'

Для простых манипуляций с текстом просто придерживайтесь комбо grep/sed. Если вам нужна более сложная обработка, переходите на awk или perl.

Моя первая мысль - просто использовать:

echo '{"displayName":"Amarghosh","reputation":"2,737","badgeHtml"'
    | sed -e 's/.*tion":"//' -e 's/".*//' -e 's/,//g'

, в котором число sed процессов равно одному (вы можете дать несколько команд с помощью -e).

8 голосов
/ 28 октября 2009

Вас может заинтересовать использование Perl для таких задач. В качестве демонстрации приведем скрипт Perl, который печатает желаемое число:

#!/usr/local/bin/perl
use warnings;
use strict;
use LWP::Simple;
use JSON;

my $url = "http://stackoverflow.com/users/flair/165297.json";
my $flair = get ($url);
my $parsed = from_json ($flair);
print "$parsed->{reputation}\n";

Этот скрипт требует установки модуля JSON, что можно сделать только с помощью команды cpan JSON.

5 голосов
/ 28 октября 2009

Для работы с JSON в сценарии оболочки используйте jsawk , который похож на awk, но для JSON .

json=$(curl -s http://stackoverflow.com/users/flair/165297.json)
echo $json | jsawk 'return this.reputation' # 2,747
3 голосов
/ 28 октября 2009

Мое предложение:

$ echo $json | sed 's/,//g;s/^.*reputation...\([0-9]*\).*$/\1/'

Я поставил две команды в аргументе sed:

  • s/,//g используется для удаления всех запятых, в частности тех, которые присутствуют в значении репутации.

  • s/^.*reputation...\([0-9]*\).*$/\1/ находит значение репутации в строке и заменяет всю строку этим значением.

В этом конкретном случае я обнаружил, что sed обеспечивает наиболее компактную команду без потери читаемости.

Другие инструменты для работы со строками (не только регулярные выражения) включают в себя:

  • grep, awk, perl упоминается в большинстве других ответов
  • tr для замены символов
  • cut, paste для обработки многоколоночных входов
  • bash сам с его богатым $(...) синтаксисом для доступа к переменным
  • tail, head для хранения последней или первой строки файла
2 голосов
/ 28 октября 2009

1) Как правильно проанализировать строку с помощью регулярных выражений в сценарии оболочки linux?

Инструменты, которые включают возможности регулярных выражений, включают sed, grep, awk, Perl, Python и многие другие. Даже в более новой версии Bash есть возможности регулярных выражений. Все, что вам нужно сделать, это посмотреть документы о том, как их использовать.

2) Правильно ли здесь использовать sed?

Может быть, но не обязательно.

3) Можно ли это сделать с помощью grep?

Да, может. вы просто создадите такое же регулярное выражение, как если бы вы использовали sed или другие. Обратите внимание, что grep просто делает то, что делает, и если вы хотите изменить какие-либо файлы, он не сделает это за вас.

4) Есть ли какая-либо другая команда, которая проще / более подходит?

Конечно. регулярное выражение может быть мощным, но это не обязательно лучший инструмент для использования в любое время. Это также зависит от того, что вы подразумеваете под «проще / уместнее». Другой метод, который нужно использовать с минимальным суетой в регулярных выражениях, - это использование поля / разделителя. вы ищете шаблоны, которые можно «разделить». например, в вашем случае (я скачал файл 165297.json вместо использования curl .. (но это то же самое)

awk 'BEGIN{
 FS="reputation" # split on the word "reputation"
}
{
    m=split($2,a,"\",\"")    # field 2 will contain the value you want plus the rest
                             # Then split on ":" and save to array "a"
    gsub(/[:\",]/,"",a[1])   # now, get rid of the redundant characters
    print a[1]
}' 165297.json

выход:

$ ./shell.sh
2747
2 голосов
/ 28 октября 2009

Вы можете сделать это с помощью grep. В grep witch есть ключ -o, извлекающий только совпадающую строку, а не целую строку.

$ echo $json | grep -o '"reputation":"[0-9,]\+"' | grep -o '[0-9,]\+'
2,747
2 голосов
/ 28 октября 2009

sed подходит, но вы будете вызывать новый процесс для каждого sed, который вы используете (который может быть слишком тяжелым в более сложных сценариях). grep не совсем подходит. Это инструмент поиска, который использует регулярные выражения для поиска интересующих строк.

Perl является одним из подходящих решений здесь, являясь языком сценариев оболочки с мощными функциями регулярного выражения. Он будет делать практически все, что вам нужно, не порождая отдельных процессов (в отличие от обычных сценариев оболочки Unix), и имеет огромную библиотеку дополнительных функций.

1 голос
/ 28 октября 2009

sed - совершенно правильная команда для вашей задачи, но она может быть не единственной.

grep тоже может быть полезным, но, как вы говорите, печатает всю строку. Это наиболее полезно для фильтрации строк многострочного файла и удаления ненужных строк.

Эффективные сценарии оболочки могут использовать комбинацию команд (а не только две, которые вы упомянули), используя таланты каждой из них.

0 голосов
/ 09 апреля 2017

Простой RegEx через Shell

Независимо от конкретного кода, могут возникнуть ситуации, когда вы хотите выполнить быструю замену регулярных выражений из стандартного ввода в стандартный вывод, используя оболочку простым способом, используя строковый синтаксис, подобный JavaScript.

Ниже приведены примеры для тех, кто ищет способ сделать это. Perl - лучшая ставка на Mac, так как в нем отсутствуют некоторые опции sed. Если вы хотите получить stdin как переменную, вы можете использовать MY_VAR=$(cat);.

echo 'text' | perl -pe 's/search/replace/g'; # using perl
echo 'text' | sed -e 's/search/replace/g'; # using sed

А вот пример пользовательской, многократно используемой функции регулярного выражения. Аргументы: исходная строка (или - для стандартного ввода), поиск , замена и параметры .

regex() {
    case "$#" in
        ( '0' ) exit 1 ;; ( '1' ) echo "$1"; exit 0 ;;
        ( '2' ) REP='' ;; ( '3' ) REP="$3"; OPT='' ;;
        ( * ) REP="$3"; OPT="$4" ;;
    esac
    TXT="$1"; SRCH="$2";
    if [ "$1" = "--" ]; then [ ! -t 0 ] && read -r TXT; fi
    echo "$TXT" | perl -pe 's/'"$SRCH"'/'"$REP"'/'"$OPT";
}

echo 'text' | regex -- search replace g;

0 голосов
/ 31 октября 2009

Вы можете использовать подходящую библиотеку (как уже отмечали другие):

E:\Home> perl -MLWP::Simple -MJSON -e "print from_json(get 'http://stackoverflow.com/users/flair/165297.json')->{reputation}"

или

$ perl -MLWP::Simple -MJSON -e 'print from_json(get "http://stackoverflow.com/users/flair/165297.json")->{reputation}, "\n"'

в зависимости от комбинации ОС / оболочки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...