Числовые переменные Bash в качестве параметров sed

#bash #file #parsing #variables #sed

Вопрос:

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

Код, который у меня есть, перебирает строки и определяет положение каждого повтора (с помощью счетчика) и сохраняет их как переменную (ПЕРВУЮ и КОНЕЧНУЮ). Я надеюсь, что затем я использую: sed -i '${FIRST},${END}d ${i}.log' , чтобы вырезать этот раздел файла.
Однако, когда я запускаю код, я получаю следующую ошибку: sed: -e expression #1, char 3: extra characters after command

Вот код, который считывает файлы, где «Цитировать» — это ключевое слово, идентифицирующее повторы:

 while read -r LINE ; do
    ((LCOUNT  ))
    if [[ "$LINE" =~ "Cite" ]] ; then
        ((CITE  ))
        if [[ "$CITE" = 1 ]] ; then
            FIRST=${LCOUNT}
        fi
        if [[ "$CITE" = 2 ]] ; then
            END=$((LCOUNT - 1))
        fi
    fi
done < "./${i}.log"
 

Комментарии:

1. Разве это не должно быть == или -eq ?

2. Вам нужно поработать над цитированием оболочки. Переменные оболочки подставляются только внутри " " , а не ' ' . Кроме того, программа sed и имя файла должны быть отдельными аргументами.

3. @rici Спасибо, что сработало. В моем коде имя файла и аргумент sed разделены, я, похоже, ошибся. Спасибо за ваш вклад.

4. может Cite отображаться более 3 раз в одном файле? если Cite только появляется 3 раза, это может немного ускорить события, если вы break из while петли после того, как вы получили FIRST и END ; в настоящее время, если вы (случайно) запустить скрипт 2-ой раз вы удаляете 2-й Cite блок, так что, возможно, имеет смысл установить FIRST/END на основе 2-го и 3-го случаев (т. е. "$CITE" = 2/3 )? если у вас есть доступ к более новой версии GNU awk (с поддержкой -i inplace ), ваша обработка, скорее всего, будет проходить намного быстрее (в отличие от действительно медленного while цикла sed ).

5. Покажите команду sed, которая выдает ошибки.

Ответ №1:

Ваша команда

 sed -i '${FIRST},${END}d ${i}.log'
 

это не имеет смысла. Вы вызываете sed сюда с двумя аргументами: Опция

 -i
 

и одна строка, которая буквально

 ${FIRST},${END}d ${i}.log
 

Поскольку вы использовали одинарные кавычки, расширение параметров не происходит, и вся часть передается в sed в качестве одного аргумента, который будет интерпретироваться как программа sed. sed пытается прочитать из stdin (так как вы не передали аргумент файла), и программа sed, очевидно, не имеет смысла.

Вы могли бы сделать что-то вроде

 sed $FIRST,${END}d "${i}.log"
 

Заметка в сторону, касающаяся названия вашего поста: «числовые переменные» в bash не существуют. Каждая переменная-это строка. Вы можете сделать

 typeset -i foo
 

что заставляет bash выполнить некоторую обработку, чтобы убедиться, что присвоенные строки представляют натуральные числа, но они все равно являются строками. Например,

 foo=abc  # sets foo to the string 0
foo=00005 # sets foo to the string 5
foo=5a # raises an error
 

Ответ №2:

Это может сработать для вас (GNU sed):

 sed -ni '/Cite/!{p;b};:a;n;//!ba;:b;n;p;bb' file1 file2 ... filen
 

Отключите неявную печать -n и включите редактирование на -i месте .

Если строка не совпадает Cite , распечатайте ее и повторите.

В противном случае отфильтруйте следующие строки до следующего совпадения, а затем распечатайте оставшиеся строки до конца файла.

N. B. Программа -i обрабатывает каждый файл отдельно так же, как -s и опция, но редактирует файлы на месте, поэтому сначала убедитесь, что вы используете -s опцию, и, когда результаты будут ожидаемыми, замените -i опцию.