'+' (one or more occurrences) not working with 'sed' command
MacosBashSedMacos 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