Кажется, ваш пример взят из страниц руководства.
MAN изначально проектировался как телетайп. Для жирного шрифта последовательность будет XX. Вероятно, потерялись при выводе в редактор, отсюда и двойные символы.
vi может легко удалить их.
Это довольно легко сделать в awk
. Когда вы увидите #
, определите, где в строке он находится. Затем для этой строки и всех последующих строк вырезать эту позицию символа из строки.
awk '
/#/ { pound=index($0, "#") }
{
if (pound)
print substr($0, 1, pound-1) substr($0, pound+1)
else
print
}
'
С помощью sed это можно сделать следующим образом. Поместите два маркера в начале двух линий, предварительно переместив их в пространство шаблона.
Затем начните перемещать их вправо по символу за раз. Во время этого движения обратите внимание на то, что находится справа от маркеров, и примите соответствующие меры.
Остановиться, когда маркер достигнет конца пространства шаблона. Теперь уберите маркеры, так как их работа сделана, и останется то, что вам нужно. Обратите внимание на маркер \n
sed -Ee '
/#/N;/\n/!b
s/\n/&&/;s/^/\n/
:a
/\n#(.*\n.*\n)./{
s//\n\1/;ba
}
s/\n(.)(.*\n.*)\n(.)/\1\n\2\3\n/
/\n$/!ba
s/\n//;s///2
' input
Использование Perl решается следующим образом:
perl -pe '
next unless /#/;
my($n,$p) = (scalar <>);
while ( /#/g ) {
pos($n) = pos() - 1 - $p++;
$n =~ s/\G.//;
}
y/#//d;s/\z/$n/;
' input_file
Рабочий:
1. Skip lines that donot have hash char.
2. Save the next line in $n and init. $p counter which keeps track of the number of hash chars erased till now.
3. Monitor the position of the hash char in a while loop and using info generate the position of the char to be deleted in next line.
4. Erase it using the \G metachar in s///
5. In the final step remove the hash chars from present line and append the next line to it.
Показан другой метод, на этот раз использующий массивы:
perl -aF'' -ne '
print,next unless /#/;
print,last if eof;
my @I = grep { $F[$_] ne "#" } 0.. $#F;
my @N = split //, <>;
print @F[@I], @N[@I];
' input_file
Рабочий:
1. Invoke Perl to split each line on a per character basis and have it stored in the array @F anew for every line read.
2. Record the array indices for which the array element is a non hash character.
3. Readin the next line, split it on a per character basis and store in array @N.
4. Now its a matter of selecting the indices we stored in @I and fetch those from arrays @F and @N.
Метод регулярных выражений:
perl -pe '
$_.= <> unless eof;
s/\G.(.*\n.{@{[+pos]}})./$1/ while /(?=#.*\n.)/g;
' input_file
Описание:
° добавить следующую строку к текущей, если это не последняя строка.
° Запишите позиции символов решетки в первой строке с помощью цикла while.
° Затем удалите символ решетки в исходной строке и символ в соответствующей позиции в следующей строке.
° После выхода из цикла while опция -p автоматически выведет $ _на стандартный вывод.
Метод с простыми строковыми операциями:
perl -pe '
last if eof;
my $n = <>;
while ( (my $p = index($_,"#")) > -1 ) {
substr($_, $p, 1) = "" for $_, $n;
}
$_.= $n;
' input_file
Это включает в себя использование встроенного индекса для проверки позиции хэша, а затем его использование во встроенной подстроке два раза... в первой и следующей строках.
Эти методы повторяются для каждой пары строк (1 и 2; 3 и 4; etc ), обрабатывая столько #
символов, сколько есть в первой строке каждой пары, и предполагая, что две строки каждой пары имеют одинаковую длину.
Совместимость с GNU awk (Linux )и BSD awk (Mac ).
Использование подстрок:
awk '{ a=$0 ; gsub(/#/,"",$0) ; print $0 ; getline ; for (n=1;n<=length(a);n++) if ( substr(a,n,1) != "#" ) printf "%s",substr($0,n,1) ; printf "%s",RS }' file.txt
Тот же код, переформатированный для более узких экранов:
awk '{
a=$0 ;
gsub(/#/,"",$0) ;
print $0 ;
getline ;
for (n=1;n<=length(a);n++)
if ( substr(a,n,1) != "#" )
printf "%s",substr($0,n,1) ;
printf "%s",RS
}' file.txt
a=$0
gsub(/#/,"",$0) ; print $0
#
из первой строки (, а не из копии ), затем распечатать измененную первую строку. getline
for (n=1;n<=length(a);n++)
if ( substr(a,n,1) != "#" )
#
,… printf "%s",substr($0,n,1)
printf "%s",RS
Использование массивов:
awk '{ c=d="" ; elements=split($0,a,"") ; getline ; split($0,b,"") ; for (n=1;n<=elements;n++) if (a[n]!="#") { c = c a[n] ; d = d b[n] } ; print c ; print d }' file.txt
Переформатирован для более узких экранов:
awk '{
c=d="" ;
elements=split($0,a,"") ;
getline ;
split($0,b,"") ;
for (n=1;n<=elements;n++)
if (a[n]!="#")
{ c = c a[n] ; d = d b[n] } ;
print c ;
print d
}' file.txt
c=d=""
elements=split($0,a,"")
elements
. getline
split($0,b,"")
for (n=1;n<=elements;n++)
if (a[n]!="#")
#
,… { c = c a[n] ; d = d b[n] }
n
. print c ; print d
Внимание:Версия awk для Mac (BSD )не обрабатывает элементы массива автоматически в порядке номеров. Сначала это дало мне удивительные результаты.
The order in which a ‘for (indx in array)’ loop traverses an array is undefined in POSIX awk and varies among implementations. gawk lets you control the order by assigning special predefined values to PROCINFO["sorted_in"].
Элементы по-прежнему нумеруются 1,2,3,...
во время создания с помощью split
, как и в GNU awk, но BSD awk не обязательно видит их в таком порядке при использовании for (n in array)
. Таким образом, вы получите зашифрованную тарабарщину.
Чтобы обойти это, вы можете сохранить длину массива (количество элементов )при создании массива — например, elements=split($0,a,"")
— и затем перебирать элементы, используя for (n=1;n<=elements;n++)
, как я' я сделал здесь.
Пример ввода(file.txt
):
abcdb#lae#blabl#a
abc~bola~xblabl~a
#alpha#beta#gamma#delta#epsilon#
abcdefghijklmnopqrstuvwxyzabcdef
Пример вывода:
abcdblaeblabla
abc~bla~blabla
alphabetagammadeltaepsilon
bcdefhijkmnopqstuvwyzabcde
awk '{gsub(/#/,"")sub(/bola~x/,"bla~")sub(/~a$/,"a")}1' file
output
abcdblaeblabla
abc~bla~blabla
С помощью gnu awk с использованием gensub
awk '
/#/{
a=$0
b=length()
getline
$0=a RS$0
while($0!=a){
a=$0
$0=gensub("([^#]*)#(.{"b--"}).","\\1\\2",1)}
}1' infile
Объяснить:
/ #/ :для каждой строки с#
a=$0 :сохранить строку в a
b=длина():получить длину в b
getline :получить следующую строку
$0=a RS$0 :добавить предыдущую строку, хранящуюся в a, в начало буфера $0, за которым следует RS в качестве разделителя записей
Теперь $0 содержит 2 строки
в то время как ($0!=a):в то время как строка, хранящаяся в a, отличается от буфера $0
a=$0 :получить буфер $0 в a
$0=gensub (" ([^ #] *)#(.{"b --"} ).","\\1\\2",1):удалите первый #в $0 и соответствующий символ во второй строке
Одновременно уменьшить (b --)длину первой строки на 1, потому что 1 #было удалено
1 :когда в первой строке больше нет #выведите $0