Я пытаюсь найти команду Linux, которая могла бы дать мне текст между [ и ]. Я пробовал стандартные grep и sed, но пока ничего не помогло. Скажем, текст находится в LOGS. нравиться -
Starting mongo client..
Connecting to truststore.pki.rds.amazonaws.com (99.84.66.9:443)
global-bundle.pem 100% |********************************| 183k 0:00:00 ETA
MongoDB shell version v4.0.6
connecting to: mongodb://XXXx.amazonaws.com:27017/?authSource=XXX&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("XXXXXXX") }
MongoDB server version: 5.0.0
WARNING: shell and server versions do not match
----------------------------------------------------------------------------------------------------
Listing Existing set of collections
----------------------------------------------------------------------------------------------------
[
"10w",
"11w",
"Test1",
"Test2",
"QA_Testing",
"QueuesTest",
"TestPagination",
]
Мне нужен был текст только с именами этой коллекции внутри []
Пробовал до сих пор
echo "$LOGS" | grep -o "\[.*\]"
echo "$LOGS" | sed -n 's/.*\[\([^]]*\)\].*/\1/p'
echo "$LOGS" | grep -o '\[\K[^\]]+'
echo "$LOGS" | awk -F'[][]' '{for(i=2;i<=NF;i+=2) print $i}'
Никто из них пока не помог. Они не показывают никаких ошибок, но и никакого вывода. Может ли кто-нибудь помочь с правильной командой, которая может мне помочь?
первый (echo | grep
) у меня работает; 2-й и 4-й почти работают, за исключением того, что литеральные [
и ]
удаляются (довольно легко убедиться, что они добавлены обратно); пожалуйста, обновите вопрос, указав полный вывод для каждой из ваших 4 попыток кодирования
4-я попытка предназначена для анализа нескольких наборов []
из одной строки ввода; может ли ваш ввод включать несколько пар []
? если «да», то укажите это в вопросе (и желательно покажите пример ввода и ожидаемый результат)
@EdMorton: эти команды не дали никакого результата. Извините, я пропустил это упомянуть
Покажите желаемый результат для этого примера ввода в вашем вопросе (без комментариев).
Ваше недавнее редактирование превратило этот вопрос в совершенно другой вопрос, чем тот, который вы изначально задали, с лучшим возможным решением, чем предлагаемые регулярные выражения. Вам следует вернуть этот вопрос в том виде, в котором вы его задали, а затем задать новый вопрос о анализе этого совершенно другого формата ввода (и добавить точный ожидаемый результат), иначе все, кто пытался вам помочь, просто тратили свое время.
$ echo "$logs" | grep -o '\[.*]'
[apple, pineapple, wood-apple]
$ echo "$logs" | sed -n 's/.*\(\[.*]\).*/\1/p'
[apple, pineapple, wood-apple]
$ echo "$logs" | awk -F'[][]' '{print "[" $2 "]"}'
[apple, pineapple, wood-apple]
$ echo "$logs" | awk 'match($0,/\[.*]/){print substr($0,RSTART,RLENGTH)}'
[apple, pineapple, wood-apple]
$ echo "$logs" | gawk 'match($0,/\[.*]/,a){print a[0]}'
[apple, pineapple, wood-apple]
$ echo "$logs" | gawk '{print gensub(/.*(\[.*]).*/, "\\1", 1)}'
[apple, pineapple, wood-apple]
$ [[ "$logs" =~ \[.*] ]] && echo "${BASH_REMATCH[0]}"
[apple, pineapple, wood-apple]
Для команды grep
требуется расширение -o
, отличное от POSIX, предоставляемое GNU grep, последние две команды awk
требуют GNU awk для не-POSIX расширений gensub()
и третьего аргумента match()
. Все остальное будет работать в любой версии инструментов, но, поскольку вы используете Linux, у вас, вероятно, все равно есть инструменты GNU.
Вышеупомянутое будет делать то, что вы просили, учитывая одну пару совпадающих [...]
в строке, как показано в вашем вопросе, но делать разные вещи для несовпадающих, множественных, вложенных и/или перекрывающихся пар [...]
в строке - если у вас есть такие об этих ситуациях и не можете решить эту проблему самостоятельно, тогда задайте новый вопрос об этом, показывающий, как вы хотели бы, чтобы эти случаи рассматривались.
Я использую logs
вместо LOGS
по причинам, описанным в Правильная заглавная буква переменных Bash и сценария оболочки.
Привет @Эд Мортон, спасибо за подробный отчет. Спасибо и за ваше время. Я думаю, что в моем случае они не выдают никакого вывода, так как между ними выглядят символы новой строки. Я обновил описание, добавив более конкретное описание к моему сценарию. Можете ли вы проверить один раз и помочь?
Вы можете извлечь строки между скобками, а затем упорядочить их после того, как они у вас появятся. Например;
Используя awk
:
echo "$logs" | awk -F'[][]' '{print $2}'
Используя sed
:
echo "$logs" | sed -n 's/.*\[\([^]]*\)\].*/\1/p'
Используя grep -oP
:
echo "$logs" | grep -oP '(?<=\[)[^]]*(?=\])'
Вернут только «яблоко, ананас, лесное яблоко». Если это необходимо, вы можете добавить/объединить/добавить скобки после их получения.
Изменить. Основываясь на изменениях редактирования и комментариев автора, я добавил новое решение следующим образом.
Ваш ввод $logs
может быть обработан, например:
awk
:echo $logs | awk '/\[/{flag=1; next} /\]/{flag=0} flag {printf "%s", $0}'
/\[/{flag=1; next}
этот раздел устанавливает флаг, когда встречается [. /\]/{flag=0}
этот раздел сбрасывает флаг при обнаружении ]. Последняя часть печатает строки, пока установлен флаг, эффективно объединяя многострочный ввод.
sed
:echo $logs | sed -n '/\[/,/\]/p' | sed ':a;N;$!ba;s/\n//g' | sed 's/.*\[\(.*\)\].*/\1/'
Вам придется использовать sed
несколько раз. Сначала находят строки между [ и ]. Второй объединяет все строки вместе, а последний извлекает содержимое между [ и ].
grep
и tr
:echo $logs | grep -oP '(?<=\[)[\s\S]*(?=\])' | tr -d '\n'
Раздел grep
соответствует всем символам между [ и ] (включая символы новой строки), а раздел tr
удаляет символы новой строки, чтобы создать одну строку.
Спасибо за ваше время. Я думаю, что в моем случае они не выдают никакого вывода, так как между ними выглядят символы новой строки. Я обновил описание, добавив более конкретное описание к моему сценарию. Можете ли вы проверить один раз и помочь?
обновил мой ответ на основе вашего изменения вопроса. надеюсь, это поможет!
echo $logs
будет делать разные вещи в зависимости от версии echo
, содержимого logs
, каталога, из которого вы его запускаете, настроек переменных среды и т. д. Всегда заключайте переменные в кавычки, см. mywiki.wooledge.org/Quotes. Кроме того, tr -d '\n'
превращает входные данные в выходные данные, которые больше не являются допустимым текстовым «файлом» POSIX, и поэтому любой последующий вызов инструмента обработки текста, такого как grep, sed или awk, делает с этим неопределенное поведение. Это почти никогда не лучший подход к чему-либо.
Одна из вещей, которую echo $logs
БУДЕТ сделать, — это превратить все пробелы, включая символы новой строки, в одиночные пустые символы, чтобы последующая передача этого в ваш awk-скрипт с использованием переменной-флага не работала.
Спасибо большое @burcu. Это помогло
По крайней мере, для вашего значения LOGS
(вы не указали общий формат текста) в bash должно работать следующее:
LOGS='[apple, pineapple, wood-apple]'
echo ${LOGS//[][]/}
//
вызывает удаление всех вхождений шаблона. Шаблон представляет собой шаблон подстановочного знака (т. е. glob), в данном случае класс символов [ ... ]
, содержащий два символа ][
.
Я использовал ответ, предоставленный бурку, но tr
перед тем, как перейти к grep
:
echo "$logs" | tr -d '\n' | grep -oP '(?<=\[)[\s\S]*(?=\])'
В моем случае сработало.
echo $logs
будет делать разные вещи в зависимости от версии echo
, содержимого logs
, каталога, из которого вы его запускаете, настроек переменных среды и т. д. Всегда заключайте переменные в кавычки, см. mywiki.wooledge.org/Quotes. Кроме того, tr -d '\n'
превращает входные данные в выходные данные, которые больше не являются допустимым текстовым «файлом» POSIX, и поэтому любой последующий вызов инструмента обработки текста, такого как grep, sed или awk, делает с этим неопределенное поведение. Это почти никогда не лучший подход к чему-либо.
В любом случае tr -d '\n'
не делает ничего полезного, поскольку echo $logs
уже преобразует все символы новой строки в пробелы, так что tr
удаляет только новую строку с конца строки (т. е. искажает ввод в grep
).
Ответ Бурджу идеален. Поскольку я предпочитаю использовать оператор if
в awk
, вот мой ответ:
awk '{
if ($0 == "[") {
in_bracket = 1
next
}else if ($0 == "]"){
in_bracket = 0
}
if (in_bracket) {
print $0
}
}' a.txt
Что делать, если скобки появляются внутри скобок? Что, если они не придут парами?