сделать вывод 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он и подобные сложности?

zetah
источник

Ответы:

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.

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

Я предпочитаю этот путь

grep -m1 'some-pattern' some-file | sed -n 's/.* //p' | tr -d '\n'
Стивен Пенни
источник
2

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

grep -m1 'some-pattern' some-file | sed -n 's/.* //p' | tr -d "\n" | tr -d "\r"
Funky_Pandy
источник
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.

Джон
источник