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

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++   ;

debería cambiar a:

    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++    ;

Aquí está mi guión:

    #!/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?

preguntado el 24 de agosto de 12 a las 00:08

By the way, in BRE you can use \{1,\} en lugar de + -

@cdarke, I don't understand, does that also give u multiple spaces? -

/ \{1,\}/ means "one or more spaces", yes. -

@cdarke your answer is great. I edited the accepted answer to include your helpful comment! -

6 Respuestas

Si está utilizando base de datos GNU entonces necesitas usar sed -r que fuerzas sed to use extended regular expressions, including the wanted behavior of +. Vea 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).

respondido 30 mar '16, 07:03

-r seemed to be an illegal option but I did a man sed for use of extended regular expressions and it showed up '-E'. Tried it and Bingo! it worked! Thanks! But I'm confused now, the use of '*' worked but for the use of '+' I had to use the -E flag? - Siddhartha

Am I correct in that you are using OS X? -r trabaja para GNU sed, pero OS X sed indeed needs -E to use the extended (modern) regular expressions. Both make a distinction between enlace y modernas regular expressions and + is interpreted as a ordinary character in the enlace funcionamiento de sed. Vea esta referencia: Obsolete (''basic'') regular expressions differ in several respects (...) '+' and '?' are ordinary characters (...). - Sico

Yeh use -E for OSX instead of -r - Robar

If you use homebrew on OS X, you can install the GNU version of sed (gnu-sed) y usa el gsed command to emulate the normal behavior. (I do this to avoid having to learn the different behaviors of UNIX/BSD sed) - andiras

@ThorSummoner: not just *nix, include the .Net engine, JavaScript, Perl (which is now different to PCRE), Python, Java, etc... See choonsiong.com/public/books/… - oscuro

You have to preceed + con un \, De lo contrario sed tries to match the character + misma.

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

Algunas implementaciones de sed even support the -i option that enables changing the file en su lugar.

Respondido 24 ago 12, 03:08

preceding with \ didn't work.. -i flag gives the error: sed: -i may not be used with stdin - Siddhartha

the accumulation doesn't work :( I couldn't find how to next sed commands online, is using 'awk' a better option? if so how? Appreciate any help. - Siddhartha

@ Siddhartha: -i only works with files, not with stdin. How could you change stdin in place? You could also try semicolons for accumulation: sed -e 's///;s///;...' - enfermedad

Ok so I got the accumulation to work, but I can't get the -E flag to fit in anywhere!: - Siddhartha

I don't think MacOS sed admite múltiples -e options. Use semicolons or newlines between the individual script commands, and put them all in a single quoted string. Also on MacOS the -i option needs an argument; you can pass it an empty string if you don't want a backup. So sed -i '' -E 's///;s///;...' "$filename" - triples

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)

Respondido 17 Oct 18, 16:10

This is what I've always used in its place. It works with everything. It's not really a hack, just a modification of "zero or more" - "one plus zero or more" = "one or more" - jon v

May not be the cleanest solution. But if you want to avoid -E y -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 o más ces

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.

Respondido 28 Feb 18, 20:02

Esto podría funcionar para ti:

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

Respondido 24 ago 12, 06:08

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

Respondido el 15 de enero de 16 a las 16:01

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.