“ +”(一次或多次)不能使用“ sed”命令

我试图通过去除不必要的空白、空行和括号中间的空格来优化代码,所以:

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


a++   ;

应改为:

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

它确实适用于括号和空行,但是它忘记将多个空格缩减为一个空格:

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

这是我的剧本:

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

还有,是否有办法使这个脚本更简洁,例如删除或减少命令的数量?

43437 次浏览

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.

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).

This might work for you:

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

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)

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

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.