1

This question already has an answer here:

I know that similar questions have been asked on this forum but, as far as I can see, none of them addressed the problem of patterns being in different lines. Namely, given a text file

( one ) ( two ) (

three

)

four

How may I delete everything that is between each '(' and ')' pair, even when the elements of the pair are on different lines? The desired result is

() () ()

four

marked as duplicate by don_crissti, glenn jackman, roaima, Archemar, αғsнιη Mar 9 '18 at 7:26

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

2

You can use perl: slurp the whole input as a single string, and use the s flag on the s/// command to indicate the newlines are to be treated as plain characters:

perl -0777 -pe 's/\(.*?\)/()/sg' <<END
( one ) ( two ) (

three

)

four
END
() () ()

four
  • Does this treat STDIN as a stream or read it all into memory? Also, is -0777 actually required? It's working without that flag for me. – Jay Taylor Mar 8 '18 at 20:24
  • It reads it into memory, and the -0777 option is required here. You'll have to demonstrate what you're doing to prove to me it isn't. – glenn jackman Mar 8 '18 at 20:30
  • Ah-ha! So if you pass the string like this: < <(echo 'something...)` then it works without -0777 flag, but when passing to stdin with a heredoc the flag is needed for it to work. Thanks Glenn. – Jay Taylor Mar 8 '18 at 21:31
  • In your process substitution, do you have any newlines? Or just a single echo statement? – glenn jackman Mar 8 '18 at 21:35
  • Slight correction: I used echo -e ... – Jay Taylor Mar 9 '18 at 0:39
0

Python alternative:

python -c 'import sys,re; print(re.sub(r"\([^()]+\)","()",sys.stdin.read().strip()))' <file

The output:

() () ()

four
0

This can be solved with a simple state machine in Python.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import fileinput
import sys

active = True
for line in fileinput.input():
    for ch in line:
        if ch == '(':
            sys.stdout.write(ch)
            active = False
        elif ch == ')':
            sys.stdout.write(ch)
            active = True
        elif active:
            sys.stdout.write(ch)

Runnable Solution

Usage:

$ echo '( one ) ( two ) (

three

)

four' | python /tmp/statemachine.py

Output:

() () ()

four
0

Using sed and will handle even if nested parentheses is there.

sed -z 's/[^()]*)/)/g' infile

Input:

( (zero) one ) ( two ) (

three

)

((((nested))here)end) last
four

Output:

( ()) () ()

(((()))) last
four

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