'+' (one or more occurrences) not working with 'sed' command

MacosBashSed

Macos Problem Overview


I'm trying to refine my code by getting rid of unnecessary white spaces, empty lines, and having parentheses balanced with a space in between them, so:

    int a = 4;
    if ((a==4) ||   (b==5))

    a++   ;

should change to:

    int a = 4;
    if ( (a==4) || (b==5) )
    a++ ;

It does work for the brackets and empty lines. However, it forgets to reduce the multiple spaces to one space:

    int a = 4;
    if ( (a==4) ||   (b==5) )
    a++    ;

Here is my script:

    #!/bin/bash
    # Script to refine code
    #
    filename=read.txt

    sed 's/((/( (/g' $filename > new.txt
    mv new.txt $filename

    sed 's/))/) )/g' $filename > new.txt
    mv new.txt $filename

    sed 's/ +/ /g' $filename > new.txt
    mv new.txt $filename

    sed '/^$/d' $filename > new.txt
    mv new.txt $filename

Also, is there a way to make this script more concise, e.g. removing or reducing the number of commands?

Macos Solutions


Solution 1 - Macos

If you are using GNU sed then you need to use sed -r which forces sed to use extended regular expressions, including the wanted behavior of +. See man sed:

-r, --regexp-extended

       use extended regular expressions in the script.

The same holds if you are using OS X sed, but then you need to use sed -E:

-E      Interpret regular expressions as extended (modern) regular expressions
        rather than basic regular regular expressions (BRE's).

Solution 2 - Macos

You have to preceed + with a \, otherwise sed tries to match the character + itself.

To make the script "smarter", you can accumulate all the expressions in one sed:

sed -e 's/((/( (/g' -e 's/))/) )/g' -e 's/ \+/ /g' -e '/^$/d' $filename > new.txt

Some implementations of sed even support the -i option that enables changing the file in place.

Solution 3 - Macos

Sometimes, -r and -e won't work. I'm using sed version 4.2.1 and they aren't working for me at all.

A quick hack is to use the * operator instead. So let's say we want to replace all redundant space characters with a single space: We'd like to do:

sed 's/ +/ /'

But we can use this instead:

sed 's/  */ /'

(note the double-space)

Solution 4 - Macos

May not be the cleanest solution. But if you want to avoid -E and -r to remain compatible with both versions of sed, you can do a repeat character cc* - that's 1 c then 0 or more c's == 1 or more c's.

Or just use the BRE syntax, as suggested by @cdarke, to match a specific number or patternsc\{1,\}. The second number after the comma is excluded to mean 1 or more.

Solution 5 - Macos

This might work for you:

sed -e '/^$/d' -e ':a' -e 's/\([()]\)\1/\1 \1/g' -e 'ta' -e 's/  */ /g' $filename >new.txt

Solution 6 - Macos

on the bash front;

First I made a script test.sh

cat test.sh

#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
    echo "Text read from file: $line"
	SRC=`echo $line | awk '{print $1}'`
	DEST=`echo $line | awk '{print $2}'`
	echo "moving $SRC to $DEST"
	mv $SRC $DEST || echo "move $SRC to $DEST failed" && exit 1
done < "$1"

then we make a data file and a test file aaa.txt

cat aaa.txt
<tag1>19</tag1>
<tag2>2</tag2>
<tag3>-12</tag3>
<tag4>37</tag4>
<tag5>-41</tag5>

then test and show results.

bash test.sh list.txt 
Text read from file: aaa.txt bbb.txt
moving aaa.txt to bbb.txt

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSiddharthaView Question on Stackoverflow
Solution 1 - MacosSiccoView Answer on Stackoverflow
Solution 2 - MacoschorobaView Answer on Stackoverflow
Solution 3 - MacosstatueofmikeView Answer on Stackoverflow
Solution 4 - MacosdosentmatterView Answer on Stackoverflow
Solution 5 - MacospotongView Answer on Stackoverflow
Solution 6 - MacosCalvin TaylorView Answer on Stackoverflow