Рассматриваемая строка:
RUN echo '[local]\nlocalhost\n' > /etc/ansible/hosts
, похоже, запускает команду echo
и используйте символ перенаправления оболочки >
, чтобы отправить вывод команды echo
в файл / etc / ansible / hosts
.
Здесь следует отметить два момента:
В команде echo
последовательность \ n
обозначает символ новой строки ( Enter ). Таким образом, [local]
и localhost
фактически отражаются в файле в последовательных строках. Это соответствует правильному формату строфы в / etc / ansible / hosts
, как описано здесь . (Я недостаточно знаю о возможности доступа, чтобы сказать вам, почему здесь используется имя хоста localhost
вместо IP-адреса 127.0.0.1
.)
Символ перенаправления оболочки >
перезапишет (то есть сотрет и заменит) содержимое / etc / ansible / hosts
, а не добавит эту новую строфу в конец файла. (Для перенаправления и добавления в файл вместо этого используйте >>
.)
Здесь используется GNU awk
, использование POSIX awk
было бы очень неприятным (отсутствие gensub
], которым я пользуюсь не раз).
#!/usr/bin/env gawk
function join(array, result, i)
{
result = array[0];
end = length(array) - 1;
for (i = 1; i <= end; i++)
result = result "," array[i];
return result;
}
function push(arr, elem)
{
arr[length(arr)] = elem;
}
# split("", arr) is a horribly unreadable way to clear an array
BEGIN { split("", arr); }
/{part}|{chapter}/ {
l = gensub(".*{(.+)}{(.+)}{([0-9]+)}$", "\\1,\\3,\\2", "g");
if ("part" == substr(l, 0, 4)) {
if (length(arr) > 0) { print join(arr); }
split("", arr);
push(arr, gensub("^(.*),(.*),(.*)$", "\\2,\\3","g", l));
} else {
push(arr, gensub("^(.*),(.*),(.*)$", "\\3","g", l));
}
}
END { print join(arr); }
Здесь используется тот факт, что регулярные выражения являются «жадными», поэтому при каждом совпадении будет отображаться полная строка. На это потребовалось больше усилий, чем я думал поначалу.
Со следующим вводом:
\contentsline {part}{Some title here\hfil }{5}
\contentsline {chapter}{\numberline {}Person name here}{5}
blah blah
\contentsline {chapter}{\numberline {}Person name here}{5}
blah blah
blah blah
\contentsline {chapter}{\numberline {}Person name here}{5}
\contentsline {chapter}{\numberline {}Person name here}{5}
blah blah
blah blah
\contentsline {chapter}{\numberline {}Person name here}{5}
\contentsline {chapter}{\numberline {}Person name here}{5}
\contentsline {part}{Some title here\hfil }{7}
\contentsline {chapter}{\numberline {}Person name here}{7}
blah blah
blah blah
\contentsline {chapter}{\numberline {}Person name here}{7}
blah blah
\contentsline {part}{Some title here\hfil }{9}
blah blah
blah blah
\contentsline {chapter}{\numberline {}Person name here}{9}
Мы производим с помощью cat input | awk -f the_above_script.awk
:
5,Some title here\hfil ,\numberline {}Person name here,\numberline {}Person name here,\numberline {}Person name here,\numberline {}Person name here,\numberline {}Person name here,\numberline {}Person name here
7,Some title here\hfil ,\numberline {}Person name here,\numberline {}Person name here
9,Some title here\hfil ,\numberline {}Person name here
Номер страницы берется из {part}
, затем из любого {chapter}
, который происходит после {part}
включен. Это позволяет использовать несколько глав внутри отдельных частей книги.
С модулем Perl Text :: Balanced
содержимое верхнего уровня {}
может быть извлечено следующим образом:
#!/usr/bin/env perl
use strict;
use warnings;
use Text::Balanced qw(extract_bracketed);
# this will of course fail if the input is one multiple lines, as this
# is only a line-by-line parser of standard input or the filenames
# passed to this script
while ( my $line = readline ) {
if ( $line =~ m/\\contentsline / ) {
my @parts = extract_contents($line);
# emit as CSV (though ideally instead use Text::CSV module)
print join( ",", @parts ), "\n";
} else {
#print "NO MATCH ON $line";
}
}
sub extract_contents {
my $line = shift;
my @parts;
# while we can get a {} bit out of the input line, anywhere in the
# input line
while ( my $part = extract_bracketed( $line, '{}', qr/[^{]*/ ) ) {
# trim off the delimiters
$part = substr $part, 1, length($part) - 2;
push @parts, $part;
}
return @parts;
}
С помощью некоторый ввод:
% < input
not content line
\contentsline {chapter}{\numberline {}Person name here}{5}
\contentsline {part}{Title with math $\frac{a}{b}$\hfil }{15}
also not content line
% perl parser input
chapter,\numberline {}Person name here,5
part,Title with math $\frac{a}{b}$\hfil ,15
%
В TXR
@(repeat)
\contentsline {part}{@title\hfil }{@page}
@ (trailer)
@ (skip)
\contentsline {chapter}{\numberline {}@author}{@page}
@ (do (put-line `@title,@author,@page`))
@(end)
Sample data:
\lorem{ipsum}
\contentsline {part}{The Art of The Meringue\hfil }{5}
a
b
c
j
\contentsline {chapter}{\numberline {}Doug LeMonjello}{5}
\contentsline {part}{Parachuting Primer\hfil }{16}
\contentsline {chapter}{\numberline {}Hugo Phirst}{16}
\contentsline {part}{Making Sense of $\frac{a}{b}$\hfil }{19}
\contentsline {part}{War and Peace\hfil }{27}
\contentsline {chapter}{\numberline {}D. Vide}{19}
\contentsline {part}{War and Peace\hfil }{19}
Run:
$ txr title-auth.txr data
The Art of The Meringue,Doug LeMonjello,5
Parachuting Primer,Hugo Phirst,16
Making Sense of $\frac{a}{b}$,D. Vide,19
Notes:
@(trailer)
строки, в которых указан автор, не обязаны строго следовать своей части. Данные могут вводить несколько \contentsline {part}
элементов, за которыми следуют chapter
строки, совпадающие по номеру страницы. @(skip)
подразумевает поиск по всем оставшимся данным. Производительность можно повысить, ограничив диапазон путем добавления числового аргумента. Если можно предположить, что совпадение {глава}
всегда находится в пределах 50 строк после {часть}
, можно использовать @(skip 50)
.