Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I'm trying to use sed to search for a certain 'primary' pattern that may exist on several lines, with each primary pattern followed by an --unknown-- number of 'secondary' patterns.

The lines containing the pattern start with: test(header_name) On that same line is an arbitrary number of strings that come after it. I want to move those strings over to their own lines so that they each are preceded by their own test(header_name).

e.g. Original file (mytest.txt):

apples
test("Type1", "hat", "cat", "dog", "house");
bananas
oranges
test("Type2", "brown", "red", "green", "yellow", "purple", "orange");

I want it to become:

apples
test("Type1", "hat");
test("Type1", "cat");
test("Type1", "dog");
test("Type1", "house");
bananas
oranges
test("Type2", "brown");
test("Type2", "red");
test("Type2", "green");
test("Type2", "yellow");
test("Type2", "purple");
test("Type2", "orange");

This would be easy to do if we knew the number of strings per line, but in this case it is not fixed.

The clumsy way would be to do this:

while ( a line exists that starts with 'test' and contains more than two args)
do

   Keep the first and second args
   Move the rest of that line to a new line and add 'test(header)' to the front

done

But this is time consuming, especially if there are hundreds of strings.

Any ideas?

share|improve this question
    
Does the answer have to specifically be for SED, or would you accept other possible text manipulation answers (perl, awk, etc.)? I personally think the loop is going to be the best way, but those other tools may work better and someone who is more familiar with them may provide a more time efficient answer should they be available. –  Matrix Mole Jul 5 '11 at 17:33
    
I prefer sed but perl is ok too. I've been designing a tool for multiple platforms and I have been getting people to use GNU sed. Thanks –  Dan Jul 5 '11 at 17:47

2 Answers 2

Not pretty, but:

awk '
    /test\(/ {
        split($0, a)
        i=2
        while (a[i]) {
            sub(/(,|\);)$/, "", a[i])
            printf("%s %s);\n", a[1], a[i])
            i++
        }
        next
    }
    {print}
'
share|improve this answer

Ok I found a solution using a WHILE loop and SED. Yes it's messy but it is faster than the algorithm I had posted earlier!

# Look for first line that has more than two args
line_num=`sed -n -e '/test("[^"]*", "[^"]*",/{=;q}' myfile.txt`

while [ "$line_num" != "" ]
do

    # Get the first argument
    first_arg=`sed -ne ''$line_num' s/test("\([^"]*\)".*/\1/pg' myfile.txt`

    # All strings will be moved to their own line that includes 'test(first_arg)'
    sed -i -e ''$line_num' s/", "/\ntest("'"$first_arg"'", "/g' myfile.txt

    # No longer need first line after all targets moved to other lines     
    sed -i -e ''$line_num'd' myfile.txt


    # Check for remaining lines with more than two args
    line_num=`sed -n -e '/test("[^"]*", "[^"]*",/{=;q}' myfile.txt`

done


# Minor adjustments to the output (add close-quotation, close-bracket and semi-colon)
sed -i \
    -e 's/");//g' \
    -e 's/\(test("[^)]*\)/\1");/g' \
myfile.txt
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.