Aqui está um jeito Perl:
$ perl -lne '/^\*(.*)/ || print "$_$1"' file
strawberry
raspberry
blueberry
boysenberry
blahblah
blahblah
blahblah
strawberry
blueberry
blah
vegetable
pingpongtable
Explicação
O -n fará o Perl ler cada linha do arquivo de entrada, salvando-o na variável especial $_ , o -l fará com que ele i) tire novas linhas ( \n ) de cada linha e ii) adicionar uma nova linha a cada chamada de print . O -e é o script aplicado a cada linha.
-
/^\*(.*)/ : corresponde linhas que começam com um asterisco e salvam tudo depois do asterisco como $1 (é o que os parênteses fazem).
-
|| print "$_$1"' : o || é um OR lógico. Portanto, o print será executado apenas se a linha atual não iniciar com um asterisco. Nesse caso, imprimimos a linha atual ( $_ ) junto com o que estiver salvo atualmente como $1 (o padrão após o asterisco).
Como de costume, há muitas maneiras de fazer isso. Um bobo e ineficiente, mas que destaca os recursos de manipulação de strings do shell, é:
$ while read line; do
[[ $line =~ ^\* ]] && pat="${line#\*}" || printf "%s%s\n" "$line" "$pat";
done < file
strawberry
raspberry
blueberry
boysenberry
blahblah
blahblah
blahblah
strawberry
blueberry
blah
vegetable
pingpongtable
Explicação
-
while read line; do ... ; done < file : este é um loop while clássico que lerá cada linha do arquivo de entrada file e salvará como $line .
-
[[ $line =~ ^\* ]] && pat="${line#\*}" : se a linha começar com * , remova tudo depois disso (é isso que o ${line#\*} faz, para mais detalhes, veja aqui ) e salve-o como $pat .
* || printf "%s%s\n" "$line" "$pat"; : se o comando anterior falhou (então, a linha não inicia com um asterisco), imprima a linha e o valor atual de $pat .