Происходит то, что оболочка каким-то образом интерпретирует *
. Убедитесь, что все извлеченные поля всегда правильно цитируются.
Вот мое решение с gnu sed
:
sed '/\(.*\)#/{h;:y;n;/\(.*\)#/b;G;s/\(.*\)\n\(.*\)/\2\1/;by}' test.txt
Быстрое объяснение:
Вот мое решение с bash:
while IFS='' read -r x;do if [[ "$x" = *# ]] ; then if [ "$p" = "$x" ]; then p=''; else p="$x"; x=''; fi ; fi; printf '%s%s\n' "$p" "$x";done < test.txt
С gnu sed
:
sed -n -e ' /.*#$/ { p; h; b; };' \
-e '{ H; x; s/[\n[:blank:]]\+/ /; p; s/\(.*#\).*/\1/; h; }' \
file.txt
Общая идея состоит в том, чтобы сохранить строку ... #
в удерживаемом пространстве и добавить ее в начало строки при последующих не ... #
строк (в пространстве шаблона).
Использование awk
:
$ awk '/^[^ ]*#$/ { prefix = $0; print; next } { print prefix, $0 }' file
bbb-ccc-cccc#
bbb-ccc-cccc# aasdf asdas asdasa fgdg
bbb-ccc-cccc# asdfa asfdas adfaq asfa
bbb-ccc-cccc# afdaf fafa fafd afafa
bbb-ccc-cccc#
Каждая строка печатается с префиксом. Префикс берется из любой строки, которая соответствует шаблону ^ [^ ␣] * # $
, то есть состоит полностью из непробельных символов и заканчивается на #
. Такие строки печатаются без дополнительного префикса, и обработка продолжается со следующей строки ввода.
Решение Python:
#!/usr/bin/env python
import sys
prefix = ""
with open(sys.argv[1]) as fd:
for line in fd:
new_line = line.rstrip()
if new_line.endswith('#'):
prefix = new_line
else:
new_line = prefix + new_line
print(new_line)
Тестовый запуск:
$ ./append_word.py input.txt
bbb-ccc-cccc#
bbb-ccc-cccc# aasdf asdas asdasa fgdg
bbb-ccc-cccc# asdfa asfdas adfaq asfa
bbb-ccc-cccc# afdaf fafa fafd afafa
bbb-ccc-cccc#
Как это работает это просто. Мы читаем файл построчно, удаляя конечные пробелы или символы новой строки с конца. Мы записываем префикс в каждую строку, если эта строка заканчивается символом #
. Если строка не заканчивается на #
, мы знаем, что эту строку нужно изменить. Наконец, мы печатаем строку независимо от того, была она изменена или нет.
С perl
:
perl -lpe 'if (/\H+#/) {$word = $&} else {$_ = $word . $_}'
То есть, если мы найдем последовательность непустых символов ( \ H +
), за которым следует #
в строке, мы используем это ( $ &
- это то, что соответствует регулярному выражению) в качестве слова, которое нужно вставить в начало следующих строк. .
То же самое с awk
:
awk '
match($0, /[^[:blank:]]+#/) {
word = substr($0, RSTART, RLENGTH)
print
next
}
{print word $0}'
То же самое с sed
(с использованием пространства удержания для хранения слова ):
sed '
/[^[:blank:]]\{1,\}#/ {
h; # save the line in the hold space
s//\
&\
/; # put newlines on each side of the matched word
s/.*\n\(.*\)\n/\1/; # remove every thing but the word
x; # swap hold and pattern space so that now the hold
# space contains the word. And branch off:
b
}
# for the other lines:
G; # append the hold space to the pattern space
s/\(.*\)\n\(.*\)/\2\1/; # move the word to the beginning'
Если вы хотите сопоставить только слова #
, которые находятся в конце строки, замените #
на # $
во всех трех приведенных выше командах.
В баш:
#!/bin/bash
# grab one of the lines ending in #
prefix=$(egrep '#$' file | head -1)
cat file | while read line
do
# if the line ends in a #, just print it
if [[ $line =~ \#$ ]]
then
echo $line
else
# print the line prefixed with the $prefix
printf -- "%s %s\n" "$prefix" "$line"
fi
done
[[ $line =~ \#$ ]]
— регулярное выражение if,то же регулярное выражение, что и в egrep
. Если вашей оболочке это не нравится, вы можете заменить его на if egrep -q '#$' <<< line; then
.