Я хочу извлечь подстроку, соответствующую шаблону и сохранить его в файл. Строка в качестве примера:
Apr 12 19:24:17 PC_NMG kernel: sd 11:0:0:0: [sdf] Attached SCSI removable disk
Я хочу извлечь часть между скобками в этом случае [sdf]
.
Я пытался сделать что-то как grep -e '[$subtext]'
сохранить текст в скобках к переменной. Конечно, это не работает, но я ищу путь, подобный этому. Это было бы очень изящно для включения переменной в regex как это. Что я могу приложить все усилия?
Спасибо!
Возможно, лучший способ использовать только bash, но:
echo 'Apr 12 19:24:17 PC_NMG kernel: sd 11:0:0:0: [sdf] Attached SCSI removable disk' \
| sed -s 's/.*\[\(.*\)\].*/\1/'
Как указывает Юрген, это соответствует несовпадающим строкам. Если вы не хотите выводить несовпадающие строки, используйте '-n', чтобы он не выводил шаблон, и '/ p', чтобы выводить шаблон, когда он совпадает.
| sed -n 's/.*\[\(.*\)\].*/\1/p'
BASH_REMATCH
- это массив, содержащий группы, соответствующие оболочке.
$ line='Apr 12 19:24:17 PC_NMG kernel: sd 11:0:0:0: [sdf] Attached SCSI removable disk'
$ [[ $line =~ \[([^]]+)\] ]]; echo "${BASH_REMATCH[1]}"
sdf
Если вы хотите поместить это в цикл, вы можете сделать это; вот пример:
while read -r line; do
if [[ $line =~ \[([^]]+)\] ]] ; then
drive="${BASH_REMATCH[1]}"
do_something_with "$drive"
fi
done < <(dmesg | egrep '\[([hsv]d[^]]+)\]')
Этот подход не помещает внешние вызовы в цикл - поэтому оболочке не нужно fork
и exec
для запуска внешних программ, таких как sed
или grep
. Таким образом, он, возможно, значительно чище, чем другие предлагаемые здесь подходы.
Кстати, ваш первоначальный подход (с использованием grep) был не так уж далек; использование grep -o
выведет только соответствующую подстроку:
$ subtext=$(egrep -o "\[[^]]*\]" <<<"$line")
... хотя это включает скобки внутри захвата, и, следовательно, не на 100% правильно.
Сопоставить с regex, заменить с помощью группировки и печатать только если regex совпал:
sed -n "s/.*\[\(.*\)\].*/\1/p"
sed является жадным, поэтому ответы sed пропустят часть данных, если в ваших данных больше []
пар. Используйте решение grep+tr или можете использовать awk
$ cat file
[sss]Apr 12 19:24:17 PC_NMG kernel: sd 11:0:0:0: [sdf] Attached SCSI removable disk [tag] blah blah
$ awk -F"[" '{for(i=2;i<=NF;i++){if($i~/\]/){sub("].*","",$i)};print $i}}' file
sss
sdf
tag