сделать вывод grep без завершающего перевода строки


8

Пожалуйста, рассмотрите этот фрагмент:

X=$(grep -m1 'some-pattern' some-file | sed -n 's/.* //p')

Я хочу поместить последнее слово в переменную, если какое-либо условие шаблона соответствует строкам в произвольном текстовом файле.

Моя проблема в том, что переменная Xимеет CR или LF или CRLF в конце, в зависимости от исходного файла, от которого я хочу избавиться, поскольку это мешает дальнейшей работе, которую я собираюсь сделать.
Я даже попробовал что-то вроде:

X=$(grep -m1 'some-pattern' some-file | sed -n 's/.* \([A-Za-z]\+\)/\1/p')

таким образом ожидая, что sedвывод будет ограничен, [A-Za-z]+но все еще есть эти байты неприятности внутри переменной X.

Как я могу избавиться от этого, не используя слишком много кода, например, посмотреть, какие байты находятся в конце, xxdзатем cutон и подобные сложности?

Ответы:


4

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

x=$(awk '/some-pattern/ { sub(/\r$/, "") ; printf("%s", $NF) ; exit }' some-file)

Подстановка позволяет избежать проблемы с окончаниями строк CRLF.

sub(/\r$/, "")удаляет завершающий CR, если он существует. Как awkтрактует в \nкачестве разделителя записи (строки), вам не нужно раздеваться, так как она не в данных, смотрели.

printf("%s", $NF)печатает последнее поле ( $NF) без завершающего символа новой строки ( printи некоторые другие awkфункции добавляют символ новой строки по умолчанию).

exitпроисходит после первых двух действий - это эквивалент m1в вашей grepкомандной строке. Это обеспечивает awkвыход после выполнения двух предыдущих команд - и поскольку эти команды выдаются после совпадения, а awk оценивает данные в режиме FIFO, будет напечатано только первое совпадение.


Спасибо, выглядит элегантно, но, к сожалению, CRLF все еще внутриX
— Zetah

:) Теперь это уже не выглядит элегантно и все равно бесполезно
— Зет

@zetah - Не будет CR, но будет LF. Мне было трудно понять, что вы хотите от вопроса, надеюсь, моя редакция делает то, что вы хотите.
— Крис Даун

Хорошо, на этот раз все идет хорошо - выведите последнее слово в строке, если эта строка удовлетворяет некоторому условию шаблона - не знаю, может быть, это понятно мне, потому что у меня есть эта проблема, а потом трудно объяснить как не говорящий по-английски , В любом случае, я подожду немного больше, если grep/sedвместо этого кто-нибудь обратится к этому решению awk(что я не понимаю), и если нет, то я его использую. Спасибо
— Zetah

@zetah - я добавлю объяснение, чтобы вы могли лучше понять его, одну секунду.
— Крис Даун

7

Символ ``или $()удалит символ новой строки с конца, но для этого используйте программу tr.

grep -m1 'some-pattern' some-file | sed -n 's/.* //p' | tr -d '\012\015'

Это удалит возврат каретки и / или перевод строки из строки.

Проблема может заключаться в том, как вы выводите результат. Например, по умолчанию echoдобавляется новая строка. Вы можете использовать echo -nили printf.


Это также удалит возврат каретки, который может возникнуть по всей строке, что может быть нежелательным.
— Крис Даун

Да, хотя возврат каретки в одну строку возможен, это крайне редко. -m1Гарантирует , что существует только один линейный выход, который , по всей вероятности, будет иметь возврат каретки в конце.
— Arcege

ах tr... интересно, работает как на LF, так и на CRLF файлах. Я бы подумал \010\013почему-то и тоже \f\rработает правильно. О результате: я не помещаю вывод в переменную, а как переменную, заключенную $()в шаблон для grepсоответствия - some pipe | grep -o " $(...) ". Спасибо за комментарии
— Зет


2

Это работает для меня:

grep -m1 'some-pattern' some-file | sed -n 's/.* //p' | tr -d "\n" | tr -d "\r"

0

Почему бы просто не sedсделать [\r\f]уборку

# using Bash's $'string' idiom (that decodes ANSI C escape sequences)
# cf. http://wiki.bash-hackers.org/syntax/quoting#ansi_c_like_strings
- X="$(grep -m1 'some-pattern' some-file | sed -n 's/.* //p')"
+ X="$(grep -m1 'some-pattern' some-file | sed -n -e $'s/[\r\f]*$//' -e 's/.* //p')"

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

# sample code to remove trailing \r with sed
# cf. http://en.wikipedia.org/wiki/Regular_expression#POSIX_character_classes
printf 'a b c\r' | sed -n 's/^.* \([[:alpha:]]\{1,\}\)/\1/p' | od -c
printf 'a b c\r' | sed -n 's/^.* \([[:alpha:]]\{1,\}\)[[:space:]]*/\1/p' | od -c

# keeps trailing space after c
printf 'a b c \r' | sed -n 's/^.* \([[:alpha:] ]\{1,\}\)[[:space:]]*/\1/p' | od -b

0

Обычная версия grep (включая grep -P) всегда выводит перевод строки со своим соответствием, поэтому, если у вас есть только один результат (или вы хотите удалить только последний добавленный перевод строки), достаточно просто удалить последний символ выход, который вы можете сделать, пропустив его через head -c-1.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.