sed中的命令替换

时间:2017-05-06 06:34:03

标签: bash sed

我想将文本文件的前六个字符读入一个字符串,并在该文件中使用该字符串添加其他所有非空行。这种文件的一个例子可能是:

04/17 Walmart .toys $ 70 .cash $ -70

Caltex .gas 20 $ .cheque $ -20

McDonalds .burger 1 $ .cash $ -1

每个条目,即:每个非空行,都需要一个日期,出于简单数据输入的原因,该日期仅在第一行输入。条目由1个或多个空行分隔。输出看起来像这样:

04/17 Walmart .toys $ 70 .cash $ -70

04/17 Caltex .gas 20 $ .cheque $ -20

04/17 McDonalds .burger 1 $ .cash $ -1

我可以将非空字符串与^[^@]+[ ]*.[ ]([^;{}:]+)[ ]*$之类的字符匹配,但我不知道如何为非空白行实际实现该字符串。

This Bash script对我很有吸引力,但我不知道如何在开始时插入我的字符串。

我也无法在Stack Overflow上找到我的问题的直接答案。

我尝试了一个接受文件名的脚本:

read -n 6 date < $1
sed 's/^/$(echo $date)/' | \
sed 's/^$(echo $date)\n//' | > $newName

我能够将日期与空格(例如字符串:'04 / 17')预先添加到每一行,然后从不跟随任何内容的每一行中删除它。

但是,似乎sed不接受命令替换:

sed: -e expression #1, char 10: unknown option to `s'

4 个答案:

答案 0 :(得分:5)

您应该可以使用一个sed命令执行此操作:

read -rn 6 date < "$1"
sed -E 's#^([a-zA-Z]+)#'"$date"' \1#g' "$1" > newfile

捕获组确保在插入日期之前该行至少有一个字符。

编辑:根据您问题的修订版:

newfile="output.txt"
lineone=$(head -1 "$1");

read -rn 6 date <<< "$lineone"
sed -E 's#^([a-zA-Z]+)#'"$date"' \1#g; 1s#^.*$#'"$lineone"'#' "$1" > "$newfile" 

由于您没有进行就地编辑,您可以执行$ date插入,然后返回并换出第一行,因为它最终会有两个日期。可能有“更好”的方法来执行此操作,例如使用Perl或丢失第二个sed命令,尽管这至少应该为您提供一个基本的想法,但它是如何工作的......

结果(新文件):

04/17 Walmart .toys $ 70 .cash $ -70

04/17 Caltex .gas 20 $ .cheque $ -20

04/17 McDonalds .burger 1 $ .cash $ -1
  

注意:在某些版本的sed中,扩展正则表达式的选项可以   可以是-r-E

答案 1 :(得分:4)

使用Perl:

perl -plE 'if($.==1){$d=substr($_,0,6);next}elsif(/./){s/^/$d/}' file > new

输出

04/17 Walmart .toys $ 70 .cash $ -70

04/17 Caltex .gas 20 $ .cheque $ -20

04/17 McDonalds .burger 1 $ .cash $ -1

或在备份到file.bak

的同一文件中
perl -i.bak -plE 'if($.==1){$d=substr($_,0,6);next}elsif(/./){s/^/$d/}' file

或者相同的文件没有备份

perl -i -plE 'if($.==1){$d=substr($_,0,6);next}elsif(/./){s/^/$d/}' file

或者,如果您不确定日期中的前导零,

perl -plE 'if($.==1){($d)=m|^(\d+/\d+\s)|;next}elsif(/./){s/^/$d/}' file

将匹配第一行开头的任何digit(s) / digit(s) space

作为评论中提到的l'L'l,上面也将日期添加到伪空行(其中行只看起来像空),例如它包含至少一个空格。在这种情况下,而不是/./

  • 使用/\w/ - 因此,仅将日期添加到包含至少一个单词字符的行;
  • 或使用/\S/ - 包含至少一个非空格字符

说明:

perl -plE '                    # Run the commands on every input line and print them.
    if( $. == 1) {             # If it is the 1st line
        $d = substr($_, 0, 6); # take the first 6 characters and store it to $d
        next                   # And continue to the next line.
    }
    elsif( /\S/ ) {            # Else if the line contains any nonspace character
        s/^/$d/                # add to the beginning the content of $d
    }
    ' file > new

答案 2 :(得分:3)

(like : shipping_skudetails.itemWeight copied into shyplite.width) 回答:

bash

输出:

unset n
while read -r x ; do
    case "${#n}$x" in 6) ;; 6*) x="$n$x" ;; *) n="${x:0:6}" ;; esac
    echo "$x"
done < file > newfile

答案 3 :(得分:2)

斜杠正在终止sed命令,将分隔符更改为其他内容:

"s#^#$(echo $date)#"

你也可能这样写:

"s#^#$date#"

但是请注意,这种方法通常很脆弱(正如您所发现的那样),因为您无法将变量视为文字字符串。

根据更新问题的示例,我建议使用单个awk命令进行文本处理。这样的东西可以给你样本输出:

$ cat file
04/17 Walmart .toys $ 70 .cash $ -70

Caltex .gas 20 $ .cheque $ -20

McDonalds .burger 1 $ .cash $ -1

$ awk 'NR==1{d=$1}NR>1&&NF>0{$0=d" "$0}1' file
04/17 Walmart .toys $ 70 .cash $ -70

04/17 Caltex .gas 20 $ .cheque $ -20

04/17 McDonalds .burger 1 $ .cash $ -1