Написание выражения grep со специальными символами? - PullRequest
0 голосов
/ 09 апреля 2019

Я пытался написать выражение Grep, которое будет проходить через все текстовые файлы в каталоге и возвращать только те файлы, которые содержат все шаблоны, которые я ищу. Пример входного файла будет следующим:

A   29  LIJ uniteresting_numbers    uniteresting_numbers    uniteresting_numbers
A   30  RTX uniteresting_numbers    uniteresting_numbers    uniteresting_numbers    <=B
A   31  BRN uniteresting_numbers    uniteresting_numbers    uniteresting_numbers    <=B
A   32  SJY uniteresting_numbers    uniteresting_numbers    uniteresting_numbers    <=B
A   33  MRT uniteresting_numbers    uniteresting_numbers    uniteresting_numbers
A   34  MUY uniteresting_numbers    uniteresting_numbers    uniteresting_numbers
A   35  OOP uniteresting_numbers    uniteresting_numbers    uniteresting_numbers    

Я хочу иметь возможность искать по всем файлам .txt в моем каталоге и возвращать только те файлы, которые содержат все из следующего:

A   30  RTX uniteresting_numbers    uniteresting_numbers    uniteresting_numbers    <=B
A   31  BRN uniteresting_numbers    uniteresting_numbers    uniteresting_numbers    <=B
A   32  SJY uniteresting_numbers    uniteresting_numbers    uniteresting_numbers    <=B

Если ни одного из этих трех нет, я хочу пропустить файл. Я буду знать, какой двузначный номер и трехбуквенный код я ищу в каждом конкретном случае. Я хочу ввести их в качестве переменных для ввода пользователем. Что я ищу, так это файлы, в которых все мои двузначные числа и трехбуквенные коды имеют обозначение <= B в самом конце. </p>

Here is the code I have thus far:

echo What do you want to name your output file? 
read myoutput
for file in *.txt; do
    if  grep -q "RTX$(printf '\t')*[0-9]$(printf '\t')*[0-9]$(printf '\t')*[0-9]" <"$file"; then 
        if grep -q "BRN$(printf '\t')*[0-9]$(printf '\t')*[0-9]$(printf '\t')*[0-9]" <"$file"" <"$file"; then
            if grep -q "SJY$(printf '\t')*[0-9]$(printf '\t')*[0-9]$(printf '\t')*[0-9]" <"$file"" <"$file"; then
                echo "$file" >>"$myoutput".txt

    else
        echo not found
    fi
    fi 
    fi
done

Обратите внимание, я не добавил часть, где пользователь вводит трехбуквенный код и двухзначное число. Это не должно быть ужасно. Во входных данных есть символ табуляции, разделяющий каждый из столбцов. Поскольку у меня есть это прямо сейчас, я могу искать все до последней вкладки и <= B. </p>

Я попытался без удачи:

echo What do you want to name your output file? 
read myoutput
for file in *.txt; do
    if  grep -q "RTX$(printf '\t')*[0-9]$(printf '\t')*[0-9]$(printf '\t')*[0-9]$(printf '\t')$(printf '<=B')" <"$file"; then 
        if grep -q "BRN$(printf '\t')*[0-9]$(printf '\t')*[0-9]$(printf '\t')*[0-9]$(printf '\t')$(printf '<=B')" <"$file"" <"$file"; then
            if grep -q "SJY$(printf '\t')*[0-9]$(printf '\t')*[0-9]$(printf '\t')*[0-9]*$(printf '\t')$(printf '<=B')*" <"$file"" <"$file"; then
                echo "$file" >>"$myoutput".txt

    else
        echo not found
    fi
    fi 
    fi
done

Любая помощь очень ценится. В некоторых случаях у меня будет более трех строк <= B, которые я ищу. Есть ли простой способ изменить это, чтобы искать количество строк <= B? Спасибо всем большое! </p>

EDIT: Я перешел в awk, как предлагалось

Чтобы сделать это с помощью awk, я ввел следующее:

#!/bin/bash
echo What do you want to name your output file? 
read myoutput
for file in *.txt; do
    if awk '/30/ && /RTX/ && /B/' "$file"; then
        echo it worked
    fi
done

Фраза "это сработало" появляется 6 раз. В мини-каталоге 6 файлов, на которых я тестирую этот скрипт. Только 3 из этих файлов действительно соответствуют шаблону awk. Как получить код после «then» для выполнения только на файлах, которые содержат шаблон awk? Я попробовал следующее на основе учебника здесь: https://www.thegeekstuff.com/2010/02/awk-conditional-statements

#!/bin/bash
echo What do you want to name your output file? 
read myoutput
for file in *.txt; do
    $ awk '{
    if ($2 =="30" || $3 == "RTX" || $7 == "B")
        echo it worked
}' "$file"
done

Мне не удалось. Спасибо за ваше руководство!

1 Ответ

1 голос
/ 10 апреля 2019

Хотя это может не совпадать с вашим подходом, попробуйте следующее:

myoutput="myoutput.txt"
for f in *.txt; do
    awk -v output="$myoutput" -v numbers="30 31 32" -v strings="RTX BRN SJY" '
    BEGIN {
        split(numbers, num)
        split(strings, str)
        delete matched
    }
    {
        for (n in num) {
            if (match($0, "^A\t" num[n] "\t" str[n] "\t[0-9]+\t[0-9]+\t[0-9]+\t<=B$")) {
                matched[n]++
            }
        }
    }
    END {
        for (n in num) {
            if (!matched[n]) {
                exit
            }
        }
        print FILENAME >> output
    } ' "$f"
done

Вы можете назначить переменные оболочки numbers и strings любому пользователю с произвольной длиной.

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