Sed +, как установить параметры в sed, управляют чтобы к строкам дисплея от текстового файла

list=/errors_exception.txt
cd /test
while IFS= read -r pattern ; do
    for file in * ; do
        if zcat < "$file" | grep -Fxq "$pattern"; then
            echo "$pattern found pattern in $file"
        fi
    done
done <"$list" > output

Примечания:

  • Ни одна из двух приведенных ниже строк не сделает то, что вы ожидаете:

     для ШАБЛОНА в `cat $ LIST`
    
    для ФАЙЛА в $ (ls)
     

    В обоих случаях оболочка выполняет разделение слов, которое вам не нужно. Предлагаемый выше код позволяет избежать этого.

  • Действительно ли файл errors_exception.txt находится в корневом каталоге?

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

Подробнее о разделении слов

Когда оболочка выполняет:

for PATTERN in `cat $LIST`

она запускает cat $ LIST . Когда это происходит, пробелы, табуляции и возврат каретки обрабатываются как одно и то же: разрыв слова. Таким образом, фактически, после разделения слов эта строка становится:

for PATTERN in one one two three four five six

и, когда выполняется цикл for , ШАБЛОН последовательно назначается одному, одному, двум, трем, четырем , пять и шесть.

На самом деле вам нужно, чтобы каждая строка рассматривалась как строка. Вот почему вместо этого используется конструкция while read .... done <"$ list" : в каждом цикле она считывает одну целую строку.

Та же проблема может произойти с этой строкой, если в именах файлов есть пробелы:

for FILE in $(ls)

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

$ touch "a b c"

Теперь запустите цикл for :

$ for file in $(ls); do echo $file; done
a
b
c

Циклы for запускаются три раза, хотя существует только один файл. Это связано с тем, что в имени файла есть пробелы, и после разделения слов цикл for получает три аргумента: a, b и c.

Этого легко избежать. Вместо этого используйте:

for file in *

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

Рекурсивный поиск

Если мы также хотим искать в подкаталогах сжатые файлы, мы можем использовать функцию globstar в bash следующим образом:

list=/errors_exception.txt
cd /test
shopt -s globstar
while IFS= read -r pattern ; do
    for file in **/*.gz ; do
        if zcat < "$file" | grep -Fxq "$pattern"; then
            echo "$pattern found pattern in $file"
        fi
    done
done <"$list" > output

Для этого требуется bash .

1
06.07.2014, 16:46
3 ответа

Пусть ваша оболочка расширит переменную с помощью ", а не '.

Пример:

victor@pyfg:~$ line_number=2
victor@pyfg:~$ sed -n "${line_number},${line_number}p" /etc/hosts
1.2.3.4 row-2

Так как вы распечатываете только одну строку, вы можете так же:

victor@pyfg:~$ sed -n "${line_number}p" /etc/hosts
1.2.3.4 row-2
1
27.01.2020, 23:52

Наверное, в вашем примере будет лучше, если после того, как вы найдете распечатанные данные, вы захотите, чтобы собеседник quit входного файла нашел нужные вам данные. Например:

sed 1q <INPUT

Это позволит автоматически распечатать первую строку, а затем полностью завершить процесс. Вы также можете сделать:

head -n1 <INPUT

... для достижения того же эффекта. Однако,

sed также интерпретирует адрес,диапазоны, и это могут быть /regex/,/addresses/ или комбинации двух типов. Например:

sed '9q;/LINE[0-9]/,/^$/!d' <<FILE
$(printf 'LINE %s\nLINE%s\nLINE %s\\nNOT LINE %s\n\n' $(seq 32))
FILE

###OUTPUT###

LINE2
LINE 3\nNOT LINE 4

LINE6
LINE 7\nNOT LINE 8

LINE 9

В приведенном выше примере sed dподнимает любую встреченную строку, которая делает ! не происходит между строкой, содержащей строку LINE, за которой следует [0-9] - или любой числовой символ - и строкой, не содержащей /^$/ вообще никаких символов - или пустой строкой. Таким образом, строки 1 и 5 - илиLINE [15] удаляются из вывода. И наоборот, LINE 9 распечатывается, потому что на 9-ой строке задано q, так что на этом этапе он прекращает обработку своего скрипта - что происходит перед фильтром, который его удалит.

Как было предложено в другом ответе, работа с параметрами переменных производится так же просто, как и разрешение оболочке расширить их для вас - для этого следует использовать "$parameter". Важно помнить, что недействительные входные данные будут рассматриваться как таковые. Например, по той же причине:

echo "///" | sed 's////g'     
sed: -e expression #1, char 5: unknown option to `s'

... также:

v=/ ;echo "///" | sed "s/$v//g"                                 :(
sed: -e expression #1, char 5: unknown option to `s'

Значение каждой переменной должно быть корректным скриптом sed и не может содержать разделительных символов.

0
27.01.2020, 23:52

просто для удовольствия, решение для awk:

awk -v line=2 'FNR==line' /etc/hosts
0
27.01.2020, 23:52

Теги

Похожие вопросы