Сайт | Скачать | Видео | Wiki

Автор Тема: Работа буферов Основного и Вспомогательного, и работа цикла в sed  (Прочитано 1437 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн ms-v

  • Новичок
  • *
  • Сообщений: 10
  • Репутация: +0/-0
 Помогите пожалуйста понять как работает загрузка строк в буфер и работа цикла.
Если можно поясните по шагам.
 Я много информации пересмотрел по sed, но не нашел ответа на свои вопросы.

1-й пример

#!/bin/sed -nf
# начиная со 2-й строки, содержимое буфера  (который уже содержит
# все предыдущие строки) добавляется к текущей строке.

1! G
 # при достижении последней строки - печатаем
$ p
# Заносим данные в буфер опять
 h
 
  # 1 - это адрес, означает 1-ю строку
 #  !  это символ инверсии
 #  Команда следующая после символа  " !   "
 # применяется ко всем строкам, кроме 1-й строки.
 
 #  G - Добавить новую строку к основному буферу (Буфер 1) 
 #  и затем добавить содержимое вспомогательного буфера (Буфер 2) 
 #  к содержимому основного (Буфер 1) 
 
 # $ - это символ регулярного выражения, означает  конец строки
 # p - Печать Буфера 1 (в stdout - на экран).
 # Эту команду имеет смысл использовать только при использовании опции -n.
 
 # h -  Заменить содержимое вспомогательного буфера (Буфер 2) содержимым основного (Буфер 1)


Цитировать
начиная со 2-й строки, содержимое буфера  (который уже содержит
# все предыдущие строки) добавляется к текущей строке.

Как это буфер уже что-то содержит ?
А какой именно это буфер ?

Ну например как я понимаю...

1. Открывается файл и в Буфер 1 - заводится 1-я строка.
2. Читается код и команда

1! G - сообщает, что команда G не применяется к  1-й строке
$ - означает, что 1-я строка смотрится до конца и
p - печатается на экран.

3. А вот дальше для 1-й строки команда h - что делает ???

4. Загружается 2-я строка в Буфер 1 .
5. Команда G добавляет ко 2-й строке новую, пустую строку и в Буфере 1 -  Кроме этого что-то из Буфера 2 добавляется к Буферу 1
и теперь 2-я строка и пустая строка и то-что было добавлено из Буфера 2 - выводятся на экран.
 Так что-же находится в Буфере 2 ?

А как здесь работает команда h ?

2-й пример (цикл)

#!/usr/bin/sed -rf
h
:b
# если строка последняя - печать и выход.
# h - Запись буфера в буфер2 (буфер2 - hold space (область удержания).
# : LABEL
# Безадресная команда. Она задаёт метку, для перехода командами t, T, и b.
# b [LABEL]
# Безусловный переход на метку LABEL. Если LABEL не применяется, то завершает этот
# цикл, и начинает следующий.
# b label
# Переход на метку label. Если такой метка не задана, то переход выполняется в конец
 # скрипта.


$b
# загружаем следующую строку
N
/^(.*)\n\1$/ {
# сл. строка такая-же как прошлая, выгружаем
# прошлую из области удержания, как-бы отменяя действие команды N
g
bb
}

        #N (добавление следующей строки к буферу).
#Эта команда работает так-же как n, однако новая строка не затирает буфер, а добавля
#ется к нему через \n. (см так-же info sed).

# если команда N загрузила посл. строку, печатаем две посл. строки сразу.
$b

# строки разные, мы сначала печатаем первую из них
P
# потом её удаляем
D
# и при окончании этого цикла печатается следующая строка.


Здесь то же непонятно как и в какой последовательности идет работа с Буферами 1 и 2 ?
Почему сразу применяется команда h ?
$ b - эту команду как понимать ?
bb -  а это что за команда ?

: b - ":" - означает какую-то функцию, которая определяет переход по меткам ???

Например,
: Metka - переход в коде на место где написано  Metka - вот это болеее понятно.

Подскажите пожалуйста? если кто знает алгоритм работы sed.

Оффлайн ms-v

  • Новичок
  • *
  • Сообщений: 10
  • Репутация: +0/-0
Текст файла.

Цитировать
1-я строка
2-я строка
3-я шаблон
4-я шаблон

Оффлайн sfs

  • Администратор
  • Ветеран
  • *****
  • Сообщений: 24070
  • Репутация: +173/-0
    • PuppyRus-A
Что нужно получить на выходе? Задача боевая или учебная?
« Последнее редактирование: 25 Июль 2017, 16:51:40 от sfs »

Оффлайн ms-v

  • Новичок
  • *
  • Сообщений: 10
  • Репутация: +0/-0
учебная.
Я разбираю работу sed, найденные примеры большинство скорей всего из оф. документации sed (бегло просмотрел info sed и видел идентичные примеры), но вот объяснений алгоритма работы sed, не нашел.

1-й скрипт

Следующий скрипт меняет местами строки файла (первые строки становятся последними и наоборот)

2-й скрипт

Выводит не повторяющиеся строки.

Оффлайн ms-v

  • Новичок
  • *
  • Сообщений: 10
  • Репутация: +0/-0
а вот скрипт должен переворачивать буквы в слове, но он вообще не работает

#!/usr/bin/sed -f

# пропускаем строки из одной буквы
/../! b

# Переворачиваем строку. Добавляем по пустой строке перед и после текущей.
s/^.*$/\
&\
/

# Переносим первый символ в конец
# цикл работает пока в средней строке есть символы.
tx
:x
s/\(\\n.\)\(.*\)\(.\\n\)/\\3\\2\\1/
tx

#удаляем лишние переносы строк
s/\\n//g

например, вот это понимаю так

Цитировать
#
# пропускаем строки из одной буквы
/../! b

 Не обрабатывать строки в которых 2 символа и более,
# после окончания цикла, выход из цикла
# (за это отвечает команда b, указанная без метки.)
# .. – эти символы регулярного выражения означают 2 и более символа (кроме символа \n)
# благодаря тому что все квантификаторы в sed - жадные

# b – так как команда b – это переход по метке, но так как метка не указано, то
# этот цикл завершается и начинается следующий цикл


и везде встречаются команды b или t, ":" , - но как они работают или как происходит загрузка строк в Буфер 1 или Буфер 2 , не нашел информации, хочу понять алгоритм работы

Чтобы самому решать такие задачи.

Оффлайн sfs

  • Администратор
  • Ветеран
  • *****
  • Сообщений: 24070
  • Репутация: +173/-0
    • PuppyRus-A
Я бы сделал не на sed
первые строки становятся последними и наоборот
tac
Выводит не повторяющиеся строки.
uniq

Оффлайн ms-v

  • Новичок
  • *
  • Сообщений: 10
  • Репутация: +0/-0

Смысл в том, чтобы менять конфигурационные файлы или обрабатывать логи и менять в них записи, что-то добавлять, что-то удалять, при этом сохранять форматирование файла.
 Имеется ввиду непосредственное редактирование строк, обрабатываемого файла.
  Так никто не сможет пояснить алгоритм работы sed ?

Оффлайн ms-v

  • Новичок
  • *
  • Сообщений: 10
  • Репутация: +0/-0
Я бы сделал не на sed
Это всего лишь примеры на которых пытаюсь понять алгоритм работы sed.

Оффлайн DdShurick

  • Активный участник
  • Ветеран
  • ****
  • Сообщений: 6382
  • Репутация: +162/-0
  • Старый чайник
Так никто не сможет пояснить алгоритм работы sed ?
Google сможет.
Моноблок Lenovo IdeaCentre c200 (Intel Atom D525, Intel GMA 3150)
Netbook Acer 722 c6ckk (AMD C-50 Ontario, Radeon HD 6250)
Nettop Asus Eee Box PC B202 (Intel Atom N270, intel GMA 950)
Nettop Asus Eee Box PC EB1007 (Intel Atom D425, Intel GMA 3150)

Оффлайн ms-v

  • Новичок
  • *
  • Сообщений: 10
  • Репутация: +0/-0
# Переворачиваем строку. Добавляем по пустой строке перед и после текущей.
s/^.*$/\
&\
/

Не совсем правильно ( на мой взгляд)

Вот запись в одну строку
sed -n "s/^.*$/&/p"

То есть то, что подходит под описание рег. выражения, заменить на найденное.
 Например, нашли слово "string", заменили на него же.
Если нужно добавить "пробел" перед найденной строкой и после его, тогда так:

sed -n "s/^.*$/ & /p"
« Последнее редактирование: 26 Июль 2017, 09:42:11 от ms-v »

Оффлайн sfs

  • Администратор
  • Ветеран
  • *****
  • Сообщений: 24070
  • Репутация: +173/-0
    • PuppyRus-A
Частенько пописываю на sh , но без таких дебрей sed обходился
Думаю, чем то помочь можно только четко написав что есть на входе и что нужно на выходе. Т.е. на примерах

Оффлайн ms-v

  • Новичок
  • *
  • Сообщений: 10
  • Репутация: +0/-0




Подробный разбор алгоритма работы цикла.

# 1. h - Запись буфера 1 в буфер 2 (буфер 2 - hold space (область удержания).
# 2. : - Безадресная команда. Она задает метку, для перехода командами t, T, и b.
# 3. : b_label - инициализация метки
# 4. $ - означает последнюю строку в последнем файле
# (или последнюю строку обрабатываемого файла , если файл один)
# 5. b [LABEL] - Безусловный переход на метку LABEL.
# Если LABEL не применяется, то завершает этот
# цикл, и начинается следующий.
# 6. b - Здесь команда "b" используется без указания МЕТКИ, поэтому завершается этот цикл
# и начинается следующий или выход из скрипта, если обрабатываемый файл
# был последним или один.
# 7. $ b - эта связка означает, как только обработается последняя строка данного файла
# происходит печать Буфера 1 и выход из данного файла (если это был последний
# обрабатываемый файл или файл был только один.

#  Другими словами, данная команда в скрипте будет использована только тогда, когда sed загрузив строку в Буфер 1, будет знать, что эта строка  последняя в обрабатываемом файле.

# 8. N - выполняет добавление следующей строки к буферу 1.
# новая строка не затирает буфер, а добавляется к нему через символ перевода
# строки - \n.
# То есть команда "N" из обрабатываемого файла сама берет следующую строку
# в данном случае 2-ю строку и помещает ее также в Буфер 1, в котором еще
# находится предыдущая строка, в данном случае 1-я строка,
# разделяя их "\n" - символом перевода строки
# Таким образом в Буфере 1 будет такая запись : "1-я строка\n2-я строка"
#

# В данном случае это выглядит так :

# - в обрабатываемом файле 2 одинаковых строки, идущих подряд
# 1-я строка называется - "Шаблон"
# 2-я строка то же называется - "Шаблон"
# Начинается работа скрипта, и - в Буфер 1, помещается 1-я строка,
# которая называется "Шаблон"
# Далее команда "h" - Записывает содержимое буфера 1 в буфер 2, поэтому в Буфер 2
# помещается копия 1-й строки, которая называется "Шаблон"
# Далее команда "N" из обрабатываемого файла сама берет следующую строку
# в данном случае 2-ю строку и помещает ее также в Буфер 1, в котором еще находится
# предыдущая строка, в данном случае 1-я, разделяя их "\n" - символом перевода строки
# Таким образом в Буфере 1 будет такая запись : "Шаблон\nШаблон"
# После этого выполняется набор команд указанных в фигурных скобках { ...commands ...}, но только
# в том случае, если верно регулярное выражение, которое как фильтр через себя
# пропустит строку находящуюся в Буфере 1

# 9. /^(.*)\n\1$/ - это /regexp/ - образец "регулярного выражения"
# по которому исследуется строка содержащаяся в Буфере 1
# ^ - от начала строки найти (.*) - любое количество любых символов,
# кроме символа перевода строки
# затем должен быть найден символ перевода новой строки \n,
# а затем ищется \1 - точно такие же символы (идентичные), которые
# были найдены согласно
# подвыражению (.*) и все это смориться до окончания текущей строки
# Таким образом строка в Буфере 1 - "Шаблон\nШаблон" соответствует заданному
# образцу "регулярного выражения" - /^(.*)\n\1$/
# Поэтому далее выполняется блок команд { g; b b_Label }

# 10.    g  -  данная команда , из Буфера 2 копирует строку в Буфер 1,
#  при этом затирая строку которая находится в Буфере 1 на момент данной операции
# Например, в данный момент в Буфере 2 находится строка - "Шаблон"
# и эта строка затрет строку "Шаблон\nШаблон"
# Таким образом и происходит удаление дубликатов строк, но если они
# идут сразу друг за другом.

# 11. b b_label - эта команда выполняет безусловный переход на метку : b_label, и
# начинается следующий цикл обработки строк данного файла.

# 12. Если в Буфер 1 попали строки разные, например "Строка\nШаблон",
# тогда пропускается выполнениe блока команд { g; b b_Label }

# 13. P - выполняется данная команда. Эта команда выводит содержимое
# Буфера 1 в выходной поток, (в данном случае печатает на экран)
# однако выводится из Буфера 1 только 1-я строка, от начала до первого \n,
# а именно, (напомню в Буфере 1 у нас в данный момент 2 разных строки
# "Строка\nШаблон"), выводится строка "Строка"

# 14.  D   -   эта команда только что-выведенную строку удаляет из Буфера 1,
# то есть смещает курсор за символ \n и печатается строка "Шаблон"
# Получается так "Строка\nШаблон", то есть 1-я подстрока данной строки
# «Строка\n» - не печатается, а печатается 2-я подстрока данной строки «Шаблон» 

# данный цикл закончен и начинается следующий, пока не закончатся обрабатываемые строки.


искал долго ответ, на форумах не очень хотят помогать
« Последнее редактирование: 09 Август 2017, 11:33:24 от ms-v »

Оффлайн ms-v

  • Новичок
  • *
  • Сообщений: 10
  • Репутация: +0/-0
Google сможет.

Точно не сможет, я проверил....

Оффлайн ms-v

  • Новичок
  • *
  • Сообщений: 10
  • Репутация: +0/-0
Вопрос касается использования команды - b, команда безусловного перехода.

Кратко о том , что я успел узнать:
1. sed - получает данные из файла или по конвейеру.
2. При работе, sed пользуется 2-мя переменными :
«pattern space» (область обработки) и «hold space»(область хранения).
Для удобства (нашел такое описание на ресурсах сети ), называю их,
 Буфер 1 (основной буфер) и Буфер 2 (вспомогательный буфер).
3. sed позволяет использовать набор команд, то есть создается файл , делается исполняемым, а в нем
уже расположен набор команд для обрабатываемого текста.

f.txt
Шаблон
Шаблон
Строка
4-я строка
Строка
Строка
8-я строка

Пример 2-й (слегка уточненный)
Пример 7.17.
#!/usr/bin/sed -rf
h
: b_label

# если строка последняя - печать и выход.
       $ b

      # загружаем следующую строку
N
/^(.*)\n\1$/ {

# если следующая строка такая-же как предыдущая строка, (например слово –«ШАБЛОН»)
# то есть regex обнаружил совпадение и эти 2 строки - дубликаты,
# тогда выполняется набор команд { commands },
# выгружаем предыдущую строку
# из области удержания (из Буфера 2), как-бы отменяя действие команды N
# напомню, что когда начинается очередная строка, то команда h – сначала делает
# копию данной строки и копирует ее в Буфер 2
g
b b_label
}


     

# если команда N загрузила последнюю строку, печатаем две последних строки сразу.
$ b

# если строки разные, мы сначала печатаем первую из них
P

# потом её удаляем
D
# и при окончании этого цикла печатается следующая строка.

Основные комментарии

# h - Запись буфера в буфер2 (буфер2 - hold space (область удержания).

# : b_label
# Безадресная команда. Она задаёт метку, для перехода командами t, T, и b.
# b [LABEL]
# Безусловный переход на метку LABEL. Если LABEL не применяется, то завершает этот
# цикл, и начинает следующий.
# или Если такой метка не задана, то переход выполняется в конец
# скрипта.

      # N (добавление следующей обрабатываемой строки из входного потока, к буферу 1).
      # Эта команда работает так-же как n, однако новая строка не затирает буфер 1,
      #  а добавляется к нему через \n. (см так-же info sed).
     
     # g - Замена содержимого буфера 1, на содержимое буфера2,
     # то есть из Буфера 2 содержимое затирает Буфер 1.
    # P - Печать буфера 1 – от начала, и до первого символа \n.


Цитировать
Алгоритм работы
Вот выдержка из оф.документации:

`: LABEL'
[No addresses allowed.]

Specify the location of LABEL for branch commands. In all other
respects, a no-op.

`b LABEL'
Unconditionally branch to LABEL. The LABEL may be omitted, in
which case the next cycle is started.

Перевод

`: LABEL'
[Адреса не разрешены.]

Укажите местоположение МЕТКИ для команд ветви. Во всех других
отношениях, без опций.

`b LABEL'

 Безусловный переход к Метке. Метка может быть опущена, в
в этом случае начинается следующий цикл.