How to repeat all lines containing marked segments, so that only one segment appears marked in each line in BASH?

I have a file marked with segments, identified by pairs {and }:

{One day}, {the cat said to the owl}, "{Owl}, {would you like to climb the mountain}?"
{The owl replied}, "{Yes}, {I would}."
{So the cat and owl climbed the mountain}.
{The next day}, {they went to the ocean}.

I need to duplicate all rows, so there is only one labeled segment per row. A line with four marked segments will be duplicated four times, with each line showing only one of the marked segments. The result will look like this:

{One day}, the cat said to the owl, "Owl, would you like to climb the mountain?"
One day, {the cat said to the owl}, "Owl, would you like to climb the mountain?"
One day, the cat said to the owl, "{Owl}, would you like to climb the mountain?"
One day, the cat said to the owl, "Owl, {would you like to climb the mountain}?"
{The owl replied}, "Yes, I would."
The owl replied, "{Yes}, I would."
The owl replied, "Yes, {I would}."
{So the cat and owl climbed the mountain}.
{The next day}, they went to the ocean.
The next day, {they went to the ocean}.
  • Brackets are never nested.
  • The brackets are never split line by line.
  • If this is more convenient, I could replace {it }with any other characters.

, , sed BASH ?

+3
3

(GNU sed):

sed ':a;/{/!d;s/{[^}]*}/\n&\n/;h;s/[{}]//g;s/\n/{/;s/\n/}/;G;P;s/[^\n]*\n//;s/\n{//;s/}\n//;ba' file

, ( , d b). ( - ). , , - . . . . .

:

sed ':a;/{/!d;h;s/{[^}]*}/\n&\n/;s/[{}]//g;s/\n/{/;s/\n/}/p;z;x;s/{//;s/}//;ba' file 
+2

awk,

:

awk -F, '{ line=$0; for(i=1;i<=NF;i++){ $0=line; for( j=1; j<=NF; j++){ if( i != j ){gsub(/{|}/,"",$j);}}print $0;}}' OFS=, your_file.txt

Script:

#!/bin/awk -f                                                                                                                         

BEGIN {
        FS=",";
        OFS=",";
}
{
        line=$0;
        for( i=1; i<=NF; i++){
                $0=line;
                for( j=1; j<=NF; j++){
                        if( i != j){
                                gsub(/{/,"",$j);
                                gsub(/}/,"",$j);
                        }
                }
                print $0;
        } 

}

:

sat:~# awk -f sample.awk file.txt
{One day}, the cat said to the owl, "Owl, would you like to climb the mountain?"
One day, {the cat said to the owl}, "Owl, would you like to climb the mountain?"
One day, the cat said to the owl, "{Owl}, would you like to climb the mountain?"
One day, the cat said to the owl, "Owl, {would you like to climb the mountain}?"
{The owl replied}, "Yes, I would."
The owl replied, "{Yes}, I would."
The owl replied, "Yes, {I would}."
{So the cat and owl climbed the mountain}.
{The next day}, they went to the ocean.
The next day, {they went to the ocean}.
+3

Here is one way to do this:

awk 'BEGIN{FS=OFS=", "}{for(i=1;i<=NF;i++){gsub(/{|}/,"",$0);sub(/[^".?]+/,"{&}",$i);print}}' file

$ cat file
{One day}, {the cat said to the owl}, "{Owl}, {would you like to climb the mountain}?"
{The owl replied}, "{Yes}, {I would}."
{So the cat and owl climbed the mountain}.
{The next day}, {they went to the ocean}.

$ awk 'BEGIN{FS=OFS=", "}{for(i=1;i<=NF;i++){gsub(/{|}/,"",$0);sub(/[^".?]+/,"{&}",$i);print}}' file
{One day}, the cat said to the owl, "Owl, would you like to climb the mountain?"
One day, {the cat said to the owl}, "Owl, would you like to climb the mountain?"
One day, the cat said to the owl, "{Owl}, would you like to climb the mountain?"
One day, the cat said to the owl, "Owl, {would you like to climb the mountain}?"
{The owl replied}, "Yes, I would."
The owl replied, "{Yes}, I would."
The owl replied, "Yes, {I would}."
{So the cat and owl climbed the mountain}.
{The next day}, they went to the ocean.
The next day, {they went to the ocean}.

Note. You can use [^[:punct:]]+instead [^".?]+of functions subto handle other punctuation characters.

+3
source

All Articles