#bash #awk #sed #grep
#bash #awk #sed #grep
Вопрос:
У меня есть файл, который содержит узлы и ребра графика в виде троек. Каждая строка состоит из 3 троек, но иногда текст находится между ними или в конце:
<samplenode> <sampleEdge> <samplenode>
<samplenode> sometimestheristextinbetween<sampleEdge> <samplenode> and sometimes more at the end
<samplenode> <samplereEdge> <samplenode>
Мне нужна команда, которая печатает только тройки и игнорирует промежуточный текст. Поэтому он должен содержать только промежуточные символы <>
Он может включать <
и >
или нет. Это не имеет значения, но оно должно быть разделено. Результат может выглядеть следующим образом:
<samplenode> <sampleEdge> <samplenode>
<samplenode> <sampleEdge> <samplenode>
<samplenode> <sampleEdge> <samplenode>
Я попробовал это с sed
, удалив все между двумя шаблонами (все между >
и <
), но это никогда не работало так, как я хотел.
У кого-нибудь есть решение для меня? Может быть, с помощью grep
или awk
?
Приветствия
Комментарии:
1. Можно ли оставлять пробел в конце строки?
2. Может ли
<
или>
отображаться в любом другом контексте, например, вsometimestheristextinbetween
тексте?3. @PaulHodges да, все в порядке.
4. @EdMorton Нет, они не отображаются ни в каком другом контексте
Ответ №1:
Вот некоторые действия awk с разделителями, протестированные с использованием образца ввода.
awk -v RS="<" -F">" '{printf $1 (NR%3==1? "n": " ")}' file
samplenode sampleEdge samplenode
samplenode sampleEdge samplenode
samplenode samplereEdge samplenode
Ответ №2:
Следующее выглядит достаточно:
sed 's/[^>]*(<[^>]*>)[^<]*/1 /g'
Ответ №3:
Это может сработать для вас (GNU sed):
sed -E 's/^.*(<[^<>]*>).*(<[^<>]*>).*1.*$/1 2 1/' file
Сопоставьте шаблон с триплетом (где первый также является третьим) и замените только совпадения, разделенные пробелом.
Ответ №4:
Другой вариант sed
.
sed -E 's/>[^<]*(<*)/> 1/g'
Это соответствует тегу закрытия либо для открытия другого (или для конца строки), и заменяет на close , пробел и все, что соответствует тесту для другого открытия (поэтому пусто в EOL).
Используйте тот, который лучше читается и имеет смысл для вас.
Если вы предпочитаете не использовать -E
расширенное сопоставление с шаблоном, то
sed 's/>[^<]*(<*)/> 1/g'
Если вам не нужен пробел в EOL, добавьте обрезку.
sed -E 's/>[^<]*(<*)/> 1/g; s/ $//;'
Комментарии:
1. Не-GNU может не допускать точки с запятой, но вы можете заменить их новыми строками.
Ответ №5:
Я бы выбрал следующий awk
подход, не могли бы вы, пожалуйста, попробовать следующее, должно работать в любом виде awk
.
awk '
{
val=""
while(match($0,/<[^>]*/)){
val=(val?val OFS:"")substr($0,RSTART,RLENGTH 1)
$0=substr($0,RSTART RLENGTH 1)
}
print val
}' Input_file
Объяснение: добавление подробного объяснения выше.
awk ' ##Starting awk program from here.
{
val="" ##Nullifying val here.
while(match($0,/<[^>]*/)){ ##Running whole loop and mentioning match inside it to match everything from < till very first occurence of > in current line.
val=(val?val OFS:"")substr($0,RSTART,RLENGTH 1) ##Creating val which has sub-string of matched part here.
$0=substr($0,RSTART RLENGTH 1) ##Re-creating current line where already matched part is removed.
}
print val ##Printing val here.
}' Input_file ##Mentioning Input_file name here.
Ответ №6:
другой awk
$ awk 'BEGIN {b="<";e=">";FS="["b e"]"}
{for(i=2;i<=NF;i =2) printf "%s ", b $i e; print ""}' file
<samplenode> <sampleEdge> <samplenode>
<samplenode> <sampleEdge> <samplenode>
<samplenode> <samplereEdge> <samplenode>
Ответ №7:
grep -o
будут напечатаны только совпадающие части строки (по одному совпадению на строку вывода), а затем вы можете использовать paste
для разбиения результата на три столбца. Это зависит от наличия ровно трех совпадений в строке.
$ grep -o '<[^>]*>' file | paste - - -
<samplenode> <sampleEdge> <samplenode>
<samplenode> <sampleEdge> <samplenode>
<samplenode> <samplereEdge> <samplenode>
Комментарии:
1. если вам нужен только один разделитель пробела, добавьте
-s
или-s' '
2. Это работает, но если между ними более 23 символов
<>
, это приведет к вырезанию всего после 23-го символа.3. Спасибо, @SBKIT, это вообще не очень приятная функция
pr
для данного варианта использования. Обновлено для использованияpaste
вместо этого.
Ответ №8:
С помощью GNU awk для FPAT и предполагая, что ни <
ни >
не появляется ни в каком другом контексте:
$ awk -v FPAT='<[^>] >' '{$1=$1}1' file
<samplenode> <sampleEdge> <samplenode>
<samplenode> <sampleEdge> <samplenode>
<samplenode> <samplereEdge> <samplenode>