#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
опцию.