如何在匹配特定字符串后将时间戳(月_年)添加到文件中?

如何在匹配特定字符串后将时间戳(月_年)添加到文件中?

我想仅在匹配特定字符串后在文件内添加时间戳:

时间戳格式:03_2016

文件包含“$channel_name 政策“字符串,我想用”替换这个字符串$channel_name Policy_03_2016

我想添加时间戳的文件内容:

package_path=/LSB/Packages/Policy
channel_path=/LSB/Channels/$parent_channel_name/$channel_name Policy
erratum_path=/LSB/Errata/$erratum_type Policies/$erratum_name
errata_path =/LSB/Errata/$parent_channel_name/$channel_name Advisory Roll-Up Policy
package_path=/LSB/Packages/Unapproved/$channel_name

所需文件格式:

package_path=/LSB/Packages/Policy
channel_path=/LSB/Channels/$parent_channel_name/$channel_name Policy_03_2016
erratum_path=/LSB/Errata/$erratum_type Policies/$erratum_name
errata_path =/LSB/Errata/$parent_channel_name/$channel_name Advisory Roll-Up Policy 
package_path=/LSB/Packages/Unapproved/$channel_name

现在我正在使用以下命令将时间戳添加到文件:

sed -i "s/$channel_name Policy/$channel_name Policy_$(date +%m_%Y)/g" filename

但这个命令正在替换所有出现的政策政策_03_2016 像这样:

package_path=/LSB/Packages/Policy_03_2016
channel_path=/LSB/Channels/$parent_channel_name/$channel_name Policy_03_2016
erratum_path=/LSB/Errata/$erratum_type Policies/$erratum_name
errata_path =/LSB/Errata/$parent_channel_name/$channel_name Advisory Roll-Up Policy_03_2016
package_path=/LSB/Packages/Unapproved/$channel_name 

这个问题有什么解决办法吗?

答案1

$对于双引号内的 shell 来说是特殊的,因为它用于参数扩展(如$var, $1, $channel_name)、算术扩展(如$((1+1)))和命令替换(如$(cmd)实际上在这里使用)。

$在正则表达式中也很特殊(例如在命令的左侧s/regex/replacement/ sed),因为它是表示“主题结束”的运算符,除非您使用-E/-r来启用扩展正则表达式,它并不特殊,除非 位于$正则表达式本身的末尾或后跟\)(或\|在支持的情况下)。尽管如此,逃避它仍然是一个好习惯。

双引号内的 shell 及其sed正则表达式都支持\作为转义运算符来删除字符的特殊含义。\在这两种情况下也可以逃脱自身。

所以,在这里,你可以这样做:

sed -i "s/\\\$channel_name Policy/\$channel_name Policy_$(date +%m_%Y)/g" filename

也就是说,\\\$逃脱 \本身和\$外壳,以便\$被传递到再次逃逸的sed地方。右侧就足够了,因为命令的替换部分并不特殊。\$\$$s/regexp/replacement/

虽然不是 POSIX,但这也可以在我知道的任何 shell 中工作:

sed -i "s/[$]channel_name Policy/&_$(date +%m_%Y)/g" filename

[$]是另一种方式逃脱 $在正则表达式中。[...]匹配于字符,这里仅包含一个:$。虽然 POSIX 未指定 shell [$],但我不知道有哪个 shell 不保持原样。不过,您需要[\$]该 shell 代码兼容 POSIX。

我们还在&替换中使用它代表正则表达式匹配的字符串

另一种选择是使用单引号对于大多数字符串(其中$并不特殊),以及命令替换的双引号,仍然$在正则表达式中转义,即使它不是绝对必要的:

sed -i 's/\$channel_name Policy/&_'"$(date +%m_%Y)/g" filename

请注意,您需要$(...)使用双引号,否则将对其应用 split+glob。

答案2

正如“don_crissti”所评论的,您必须转义美元符号,否则它会尝试获取可变内容(在您的情况下为空)。

或者,如果您使用与“/”不同的分隔符会更安全,因为文件中也有斜杠。但是,只要您不在替换表达式中使用它们,这对于您的情况来说不是问题。

我的工作解决方案:

sed -i 's!\$channel_name Policy!&_'$(date +%m_%Y)'!g' policies.txt

第二个可能的改进是在替换中使用 the,&因为它正是搜索到的表达式加上一些额外的内容。

第三,在我的测试中,我只能在表达式$(date +%m_%Y)之外sed(用单引号括起来)时使命令起作用。

我也尝试过 in GNU sed(上面的行)和 with ,OSX sed但没有一个能够正确解释$(command).

相关内容