LINUX.ORG.RU

Проверка многострочных строк

 ,


0

1

Есть функция:

function _STR_CHECK () {
    local str="${1}"
    local file="${2}"

    if ! grep -q "${str}" "${file}"; then
        return 2
    fi
}

Если так, то всё ок

old='{ MODKEY|ControlMask,           XK_period,     cyclelayout,            {.i = +1 } },'
_STR_CHECK "${old}" "${FILE_CFG}"

А если так, то ломается

old=$(printf "    %s" "TAGKEYS(                        XK_9,                                  8)\n    #include \"${FILE_CFG_MY_BIND}\"")
_STR_CHECK "${old}" "${FILE_CFG}"

Т.е нужно как-то сделать проверку на многострочные строки

★★★★

Последнее исправление: bryak (всего исправлений: 1)
Ответ на: комментарий от yars068

Думаю, тут нужно изменять IFS:

Так а не обязательно тут будет конец строки ‘;’. Тут разные строки проверяются(в смысле не всегда заканчиваются символом ‘;’)

bryak ★★★★
() автор топика
Последнее исправление: bryak (всего исправлений: 2)
Ответ на: комментарий от firkax

А с чего ты взял что grep умеет искать многострочные куски? Насколько я знаю, не умеет. Хотя может быть кто поправит.

Мне, честно говоря, пофиг чем проверять(желательно, чтобы это было в стандартной поставке утилит debian)

bryak ★★★★
() автор топика
Ответ на: комментарий от firkax

Всмысле в стандартной? gcc сюда относится? Его можно через apt-get установить.

В смысле поставил чистый дебиан netinstall и там оно уже есть. Но лучше, если это не будет какой-то сорс на си, который надо собирать gcc, а чем-то из утилит, которые уже установлены

PS: на python’e я и сам могу прочитать файл, распарсить строки и всё проверить. Хотелось бы без питона\скриптоты это сделать

bryak ★★★★
() автор топика
Последнее исправление: bryak (всего исправлений: 2)

нужны опции -Pzo

 -P, --perl-regexp
              Interpret PATTERNS as Perl-compatible regular expressions (PCREs).  This option is experimental when combined with the -z (--null-data) option, and grep -P may warn of unimplemented features.

 -z, --null-data
              Treat input and output data as sequences of lines, each terminated by a zero byte (the ASCII NUL character) instead of a newline.  Like the -Z or --null option, this option can be used with commands like sort -z to process arbitrary file names.

 -o, --only-matching
              Print only the matched (non-empty) parts of a matching line, with each such part on a separate output line.
ugoday ★★★★★
()
Ответ на: комментарий от bryak

Хм, но тут цель же именно сделать так, чтобы две разных строки проверялись как одна, разве нет? Мы меняем дефолтное значение IFS, которое означает один из пробельных символов, в современных реалиях – ‘\n’, на ‘;’, тем самым, две строки будут восприниматься как одна.

yars068 ★★★★★
()
Ответ на: комментарий от yars068

Ночь, уже тупить начинаю. Я подумал, что этим ты определяешь конец сишной строки. В общем бред. Ок, я сейчас протестирую твой вариант!

bryak ★★★★
() автор топика
Ответ на: комментарий от bryak
➜  /tmp cat > horses.txt <<EOF
heredoc> Били копыта.
Пели будто:
— Гриб.
Грабь.
Гроб.
Груб. —
EOF

➜  /tmp grep -Pzq "Грабь.\nГробs" horses.txt && echo нашёл || echo не нашёл
не нашёл
➜  /tmp grep -Pzq "Грабь.\nГроб" horses.txt && echo нашёл || echo не нашёл
нашёл
ugoday ★★★★★
()
Ответ на: комментарий от BACR

Что-то у меня все три варианта не хотят проверять строку на наличие \n

if echo "${str}" | grep -q $'\n'; then
        echo "Строка содержит перенос"
    else
        echo "Строка не содержит перенос"

    fi

    if [[ "${str}" == *$'\n'* ]]; then
        echo "Строка содержит перенос"
    else
        echo "Строка не содержит перенос"
    fi

    if [[ "$str" != "${str//$'\n'/}" ]]; then
        echo "Строка содержит перенос"
    else
        echo "Строка не содержит перенос"

    fi

А так вариант нормальный

bryak ★★★★
() автор топика
Ответ на: комментарий от ugoday
old='{ MODKEY|ControlMask,           XK_period,     cyclelayout,            {.i = +1 } },'
    new='    \/\/ { MODKEY|ControlMask,           XK_period,     cyclelayout,            {.i = +1 } }, \/\/ changed\n    { MODKEY,                       XK_space,      cyclelayout,            {.i = -1 } }, \/\/ changed'
    ACTION_STR_REPLACE "${DIR_OUT}/${PATH_FINALIZER_OUT}/${FILE_CFG}" "${old}" "${new}"

    old='TAGKEYS(                        XK_9,                                  8)'
    new=$(printf "    %s" "TAGKEYS(                        XK_9,                                  8)\n    #include \"${FILE_CFG_MY_BIND}\"")
    ACTION_STR_REPLACE "${DIR_OUT}/${PATH_FINALIZER_OUT}/${FILE_CFG}" "${old}" "${new}"
_STR_CHECK () {

if echo "${str}" | grep -Pzq $'\n'; then
        echo "Строка содержит перенос"
    else
        echo "Строка не содержит перенос"

    fi

out:

Строка содержит перенос
Строка содержит перенос
2
Строка содержит перенос
Строка содержит перенос
2

Без q:

{ MODKEY|ControlMask,           XK_period,     cyclelayout,            {.i = +1 } },
^@Строка содержит перенос
    \/\/ { MODKEY|ControlMask,           XK_period,     cyclelayout,            {.i = +1 } }, \/\/ changed\n    { MODKEY,                       XK_space,      cyclelayout,            {.i = -1 } }, \/\/ changed
^@Строка содержит перенос
2
TAGKEYS(                        XK_9,                                  8)
^@Строка содержит перенос
    TAGKEYS(                        XK_9,                                  8)\n    #include "config_my_bind.h"
^@Строка содержит перенос
2
bryak ★★★★
() автор топика
Последнее исправление: bryak (всего исправлений: 4)

Зная что любители задавать вопросы в процессе накручивают доп. условия я давно ради Proof of Concept написал такое: Заменить строку со спецсимволами во многих файлах (комментарий)

Замену на поиск легко поменять. И будет тебе поиск всего и во всём.

futurama ★★★★★
()
Ответ на: комментарий от futurama

Но все поняли, так-то файл состоит из строк, которые для человека оканчиваются непечатным символом \n, который при печати переводит каретку принтера в начало строки и смещает лист бумаги на следующую строку. В принципе, текстовый файл так можно организовать – одна большая Си-строка с несколькими переводами строки и с \0 в конце последней строки.

yars068 ★★★★★
()
Ответ на: комментарий от yars068

Тогда пользуйся поиском с \0, а не … сову на глобус

man grep

       -z, --null-data
              Treat input and output data as sequences of lines,  each  terminated  by  a
              zero  byte  (the ASCII NUL character) instead of a newline.  Like the -Z or
              --null option, this option can be  used  with  commands  like  sort  -z  to
              process arbitrary file names.
futurama ★★★★★
()
Последнее исправление: futurama (всего исправлений: 1)

Т.е нужно как-то сделать проверку на многострочные строки

Ты хотя бы первую строчку мана на греп прочитал?

NAME
       grep - print lines that match patterns

Греп печатает строки, соответствующие критерию. Никаких многострочных сравнений в грепе нет.

С помощью опции -z можно сменить символ конца строки, но концептуально это ничего не меняет — в грепе построчная обработка файла. Если ты сдуру применишь -z к обычному текстовому файлу, то весь файл греп будет считать одной строкой (если в файле нет нуликов, а в текстовых файлах обычно их нет). Соответственно, если будет найдено соответствие, то распечатаются не две строки (в твоём понимании), а весь файл.

Мне, честно говоря, пофиг чем проверять(желательно, чтобы это было в стандартной поставке утилит debian)

Тогда бери перл. Регулярки в перле — лучшие. Кроме того, с помощью опций -p или -n можно забубенить всё в командной строке и не писать скрипт, например:

$ perl -gn -e "print for m{^$line1\n$line2\n}mg;" "$file"

где line1 и line2 — регулярки для первой и второй строк. Вот так может быть более понятно происходящее:

$ perl -gn -e "while ( $_ =~ m{^$line1\n$line2\n}mg ) { print $&; }" "$file"

многострочных строк

И да, в английском «multiline string» имеет смысл. Но то, что ты хочешь — «multiline line», а это хрень несуществующая.

debugger ★★★★★
()
Последнее исправление: debugger (всего исправлений: 1)
function _STR_CHECK () {
    local str="${1}"
    local file="${2}"

    if ! grep -q "${str}" "${file}"; then
        return 2
    fi
}

Кстати, где ты научился так говнокодить? В шелле 0 — true, всё, что не ноль — false. Греп возвращает 0 (true), если строки, соответвующие критерию, найдены, и 1 (false), если не найдены. Из функции возвращается результат последней команды. Ты своим if заменяешь 1 на 2. Какой в этом смысл, если и 1, и 2 — всё равно false? Проще было бы написать:

function _STR_CHECK () {
    local str="${1}"
    local file="${2}"
   grep -q "${str}" "${file}"
}

И становится видно, что такая функция вообще нафиг не нужна — проще вызвать греп напрямую.

Если что и имеет смысл, так это ловить ситуацию когда греп завершается с кодом больше 1. Это значит либо греп не сумел прочитать файлы, либо есть ошибки в командной строке. Вот такая функция имела бы смысл:

function _STR_CHECK () {
    local str="${1}"
    local file="${2}"
    local status=0
    grep -q "${str}" "${file}" || status=$?
    if (( $status > 1 )); then
       echo "Oops" >&2       
       exit 255
    fi
   return $status
}

Если греп нашёл строчки, то функция вернёт 0 (true), если не найдёт — 1 (false), если греп завершился с ошибкой — скрипт закончится.

debugger ★★★★★
()
Ответ на: комментарий от debugger

Чем это

if ! grep -q "${str}" "${file}"; then
   return 2
fi

принципиально от этого отличается?

local status=0
grep -q "${str}" "${file}" || status=$?
if (( $status > 1 )); then
   return 2
fi

По-моему наличием локальной переменной

И становится видно, что такая функция вообще нафиг не нужна — проще вызвать греп напрямую.

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

bryak ★★★★
() автор топика
Последнее исправление: bryak (всего исправлений: 1)
Ответ на: комментарий от debugger

Еще раз на свежую голову прочитал

Ты своим if заменяешь 1 на 2. Какой в этом смысл, если и 1, и 2 — всё равно false?

Это выделенный код ошибки. Используется во всех функциях. Единообразие

bryak ★★★★
() автор топика
Ответ на: комментарий от debugger

Соответственно, если будет найдено соответствие, то распечатаются не две строки (в твоём понимании), а весь файл.

У него grep -q , т.е ничего не печатается, только факт наличия обнаруживается

futurama ★★★★★
()