Используйте `sed` для замены текста в блоке кода выводом команды в верхней части блока кода - PullRequest
0 голосов
/ 26 октября 2018

У меня есть файл уценки с фрагментами кода, похожими на следующий пример:

```
$ cat docs/code_sample.sh

#!/usr/bin/env bash
echo "Hello, world"
```

Это означает, что в папке docs/code_sample.sh есть файл, содержимое которого:

#!/usr/bin/env bash
echo "Hello, world"

Я бы хотел проанализировать файл уценки с помощью sed (awk или perl тоже работает) и заменить нижнюю часть фрагмента кода на то, к чему относится приведенная выше команда bash, например на cat docs/code_sample.sh оценивает до.

Ответы [ 3 ]

0 голосов
/ 26 октября 2018

Решение только для sed проще, если у вас есть версия GNU с командой e.

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

Я начал с создания a, b и x, который является файлом разметки.

$: cat a
#! /bin/bash
echo "Hello, World!"

$: cat b
#! /bin/bash
echo "SCREW YOU!!!!"

$: cat x
```
$ cat a

foo
   bar
" b a z ! "
```
```
$ cat b

foo
   bar
" b a z ! "
```

Затем я написал s, который является sed сценарием.

$: cat s
#! /bin/env bash

sed -En '

 /^```$/,/^```$/ {

  # for the lines starting with the $ prompt
  /^[$] / {
    # save the command to the hold space
    x
    # write the ``` header to the pattern space
    s/.*/```/
    # print the fabricated header
    p
    # swap the command back in
    x
    # the next line should be blank - add it to the current pattern space
    N
    # first print the line of code as-is with the (assumed) following blank line
    p
    # scrub the $ (prompt) off the command
    s/^[$] //
    # execute the command - store the output into the pattern space
    e
    # print the output
    p
    # put the markdown footer back
    s/.*/```/
    # and print that
    p
  }

  # for the (to be discarded) existing lines of "content"
  /^[^`$]/d

}
' $*

Это делает работу и может начать вас.

$: s x
```
$ cat a

#! /bin/bash
echo "Hello, World!"
```
```
$ cat b

#! /bin/bash
echo "SCREW YOU!!!!"
```

Множество предостережений - лучше на самом деле проверить, что $ следует за строкой обратных символов и сопровождается пустой строкой, возможно, убедитесь, что в файле не было ничего поддельного для выполнения ... но это делает то, что вы спросил, с (GNU) sed.

Удачи.

0 голосов
/ 27 октября 2018

Редкий случай, когда целесообразно использовать getline:

$ cat tst.awk
state == "importing" {
    while ( (getline line < $NF) > 0 ) {
        print line
    }
    close($NF)
    state = "imported"
}

$0 == "```" { state = (state ? "" : "importing") }

state != "imported" { print }

$ awk -f tst.awk file

См. http://awk.freeshell.org/AllAboutGetline для использования getline и предостережений.

0 голосов
/ 26 октября 2018

Perl на помощь!

perl -0777 -pe 's/(?<=```\n)^(\$ (.*)\n\n)(?^s:.*?)(?=```)/"$1".qx($2)/meg' < input > output
  • -0777 глотает весь файл в память
  • -p печатает ввод после обработки
  • s/PATTERN/REPLACEMENT/ работает аналогично замене в sed
  • /g заменяет глобально, т.е. столько раз, сколько может
  • /m делает ^ совпадением начала каждой строки вместо начала всей входной строки
  • /e оценивает замену как код
  • (?<=```\n) означает «с тремя обратными кавычками и новой строкой»
  • (?^s:.*?) изменяет поведение ., чтобы также соответствовать символам новой строки, поэтому он соответствует (экономно из-за *?) остальной части предварительно отформатированного блока
  • (?=```) означает «с последующими тремя обратными кавычками»
  • qx запускает параметр в оболочке и возвращает его вывод
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...