在sed -f中使用变量(其中sed脚本在文件而不是内联中)

时间:2012-10-11 01:34:27

标签: sed

我们有一个进程可以使用包含sed命令的文件来改变管道输入。

我需要用输入值替换输入中的占位符,例如在一个-e类型的命令中,我可以运行;

$ echo "Today is XX" | sed -e "s/XX/$(date +%F)/"
Today is 2012-10-11

但是我只能在文件中指定sed个方面(然后将过程指向文件),例如。名为replacements.sed的文件可能包含;

s/XX/Thursday/

很明显;

$ echo "Today is XX" | sed -f replacements.sed
Today is Thursday

但是,如果我想使用环境变量或shell值,我找不到一种方法来扩展它,例如如果replacements.txt包含;

s/XX/$(date +%F)/

然后;

$ echo "Today is XX" | sed -f replacements.sed
Today is $(date +%F)

在文件的文本中包含双引号只会打印双引号。

有没有人知道如何在sed文件中使用变量?

5 个答案:

答案 0 :(得分:7)

这可能适合你(GNU sed):

cat <<\! > replacements.sed
/XX/{s//'"$(date +%F)"'/;s/.*/echo '&'/e}
!
echo "Today is XX" | sed -f replacements.sed

如果您没有GNU sed,请尝试:

cat <<\! > replacements.sed
/XX/{
    s//'"$(date +%F)"'/
    s/.*/echo '&'/
}
!
echo "Today is XX" | sed -f replacements.sed | sh

答案 1 :(得分:3)

AFAIK,这是不可能的。你最好的选择是:

INPUT FILE

aaa
bbb
ccc

SH SCRIPT

#!/bin/sh

STRING="${1//\//\\/}"   # using parameter expansion to prevent / collisions

shift

sed "
s/aaa/$STRING/
" "$@"

命令行

./sed.sh "fo/obar" <file path>

<强>输出

fo/obar
bbb
ccc

答案 2 :(得分:2)

正如其他人所说的那样,你不能在sed脚本中使用变量,但是你可以使用额外的前导输入来“伪造”它,它会被添加到你的保持缓冲区。例如:

[ghoti@pc ~/tmp]$ cat scr.sed 
1{;h;d;};/^--$/g
[ghoti@pc ~/tmp]$ sed -f scr.sed <(date '+%Y-%m-%d'; printf 'foo\n--\nbar\n')
foo
2012-10-10
bar
[ghoti@pc ~/tmp]$ 

在这个例子中,我正在使用进程重定向来获取sed的输入。 “重要”数据由printf生成。你可以改为使用文件,或运行其他程序。 “变量”由date命令生成,并成为脚本的第一行输入。

sed脚本占用第一行,将其放入sed的保持缓冲区,然后删除该行。然后对于任何后续行,如果它匹配双短划线(我们的“宏替换”),它将替换保持缓冲区的内容。并打印,因为这是sed的默认操作。

保持缓冲区(g,G,h,H和x命令)代表“高级”sed编程。但是一旦你理解了它们是如何工作的,它们就开辟了sed fu的新维度。

注意:此解决方案仅可帮助您替换整行。使用保持缓冲区替换行内的子串可能是可能的,但我无法想象一种方法。

(另一个注意事项:我在FreeBSD中这样做,它使用与你在Linux中找到的不同的sed。这可能在GNU sed中有效,或者可能没有;我没有测试过。)

答案 3 :(得分:0)

我同意sputnick的意见。我不相信sed能够完成这项任务。

但是,您可以动态生成该文件。

您可以将日期更改为固定字符串,例如  __DAYOFWEEK__

创建临时文件,使用sed将__DAYOFWEEK__替换为$(date +%Y)

然后使用sed -f $TEMPFILE解析您的文件。

sed很棒,但是可能是时候使用像perl这样可以动态生成日期的东西了。

答案 4 :(得分:0)

要使用sed文件在替换表达式中添加换行符,最终对我有用的是转义文字换行符。示例:在字符串NewLineHere之后添加换行符,然后对我有用:

#! /usr/bin/sed -f
s/NewLineHere/NewLineHere\
/g

不确定这很重要,但是我在Solaris unix上,所以肯定不是GNU sed。