我们的脚本中有一个sed命令,用来自variables的值replace文件内容
例如..
export value="dba01upc\Fusion_test" sed -i "s%{"sara_ftp_username"}%$value%g" /home_ldap/user1/placeholder/Sara.xml
sed命令会忽略像'\'这样的特殊字符,而用'\'replace为string“dba01upcFusion_test”,它会起作用如果我执行export export ='dba01upc \ Fusion_test'(用'\'围住'')。但不幸的是,我们的客户想要将原始文本dba01upc \ Fusion_test与单/双引号导出,并且他不想向文本添加任何额外的字符。 任何一个可以让我知道如何使sed文字放置特殊字符..
replace之前:Sara.xml
<?xml version="1.0" encoding="UTF-8"?> <ser:service-account > <ser:description/> <ser:static-account> <con:username>{sara_ftp_username}</con:username> </ser:static-account> </ser:service-account>
replace后:Sara.xml
<?xml version="1.0" encoding="UTF-8"?> <ser:service-account> <ser:description/> <ser:static-account> <con:username>dba01upcFusion_test</con:username> </ser:static-account> </ser:service-account>
提前致谢
你不能用sed强有力的解决这个问题。 只需使用awk:
awk -v old="string1" -v new="string2" ' idx = index($0,old) { $0 = substr($0,1,idx-1) new substr($0,idx+length(old)) } 1' file
啊,@ mklement0有一个很好的观点 – 为了避免被解释的转义,你需要传递arg列表中的值以及文件名,然后从中分配变量,而不是使用-v
(看到我写了很长一段时间的comp.unix.shell常见问题的总结http://cfajohnson.com/shell/cus-faq-2.html#Q24,但显然忘记了!)。
以下内容将对每一行上的每个搜索字符串进行强有力的替换( a\ta
– > e\tf
):
$ cat tst.awk BEGIN { old=ARGV[1]; delete ARGV[1] new=ARGV[2]; delete ARGV[2] lgthOld = length(old) } { head = ""; tail = $0 while ( idx = index(tail,old) ) { head = head substr(tail,1,idx-1) new tail = substr(tail,idx+lgthOld) } print head tail } $ cat file a\ta aaa\ta $ awk -f tst.awk 'a\ta' 'e\tf' file e\tf aae\tf
file
的空白是制表符。 您可以将ARGV [3]向下移动,并根据需要调整ARGC,但在大多数情况下不需要。
更新与事后的好处,目前的选择 :
sed
, 请参阅下面的 – 有点麻烦,但现在是强大的和通用的解决方案 。 awk
解决方案 ,同时也可以正确处理任意搜索和替换字符串(但不能包含诸如边界断言之类的正则表达式),请参阅Ed Morton的答案 。 bash
解决方案,并且你的输入文件很小 ,保留多个尾随换行符并不重要,请参阅Charles Duffy的答案 。 如果您需要一个完整的第三方模板解决方案 ,请考虑j2cli
,一个Jinja2
的模板化CLI – 如果您有Python和pip
,请使用sudo pip install j2cli
。
简单的例子(请注意,由于替换字符串是通过文件提供的,所以这可能不适用于敏感数据;请注意双括号( {{...}}
):
value='dba01upc\Fusion_test' echo "sara_ftp_username=$value" >data.env echo '<con:username>{{sara_ftp_username}}</con:username>' >tmpl.xml j2 tmpl.xml data.env # -> <con:username>dba01upc\Fusion_test</con:username>
如果您使用sed
,则需要仔细转义搜索和替换字符串 ,因为:
sed
不支持使用文字字符串作为替换字符串 – 它总是翻译替换字符串中的特殊字符/序列。 以下使用了两个通用的帮助函数来执行这个转义(引用) , 这些转义应用了“可以用sed可靠地转义正则表达式字符吗? :
#!/usr/bin/env bash # SYNOPSIS # quoteRe <text> # DESCRIPTION # Quotes (escapes) the specified literal text for use in a regular expression, # whether basic or extended - should work with all common flavors. quoteRe() { sed -e 's/[^^]/[&]/g; s/\^/\\^/g; $!a\'$'\n''\\n' <<<"$1" | tr -d '\n'; } # ' # SYNOPSIS # quoteSubst <text> # DESCRIPTION # Quotes (escapes) the specified literal string for safe use as the substitution string (the 'new' in `s/old/new/`). quoteSubst() { IFS= read -d '' -r < <(sed -e ':a' -e '$!{N;ba' -e '}' -e 's/[&/\]/\\&/g; s/\n/\\&/g' <<<"$1") printf %s "${REPLY%$'\n'}" } # The search string. search='{sara_ftp_username}' # The replacement string; a demo value with characters that need escaping. value='&\1%"'\'';<>/|dba01upc\Fusion_test' # Use the appropriately escaped versions of both strings. sed "s/$(quoteRe "$search")/$(quoteSubst "$value")/g" <<<'<el>{sara_ftp_username}</el>' # -> <el>&\1%"';<>/|dba01upc\Fusion_test</el>
quoteRe()
和quoteSubst()
正确处理多行字符串 。
sed
默认只读一行,那么在多行字符串中使用quoteRe()
只在同时显式读取多行(或所有行)的sed
命令中才有意义。 quoteRe()
总是可以安全地使用命令替换( $(...)
) ,因为它总是返回一个单行字符串(输入中的换行符被编码为'\n'
)。 quoteSubst()
与具有尾随换行符的字符串一起使用,则不得使用$(...)
,因为后者将删除最后一个尾随的换行符,并因此中断编码(因为quoteSubst()
转义实际换行符,返回的字符串将在一个悬而未决的\
)。
IFS= read -d '' -r escapedValue <(quoteSubst "$value")
将转义值读入单独的变量中,然后在sed
命令中使用该变量。 这可以通过bash buildins来完成 – 没有sed,awk等。
orig='{sara_ftp_username}' # put the original value into a variable new='dba01upc\Fusion_test' # ...no need to 'export'! contents=$(<Sara.xml) # read the file's content into new_contents=${contents//"$orig"/$new} # use parameter expansion to replace printf '%s' "$new_contents" >Sara.xml # write new content to disk
有关使用参数扩展进行字符串替换的信息,请参阅BashFAQ#100的相关部分 。