我有一根像这样的绳子:
#
pap
基本上翻译为
\t#\n\tpap
,我想将其替换为:
#
pap
python
翻译为
\t#\n\tpap\n\tpython
。
用
sed
以多种方式尝试过此操作,但它不起作用,可能是因为 sed
以不同的方式使用新行。我尝试过:
sed -i "s/\t#\n\tpap/\t#\tpython\n\tpap/" /etc/freeradius/sites-available/default
...以及许多其他不同的方式都没有结果。知道在这种情况下我该如何更换吗?
用 gawk 尝试一下这行:
awk -v RS="\0" -v ORS="" '{gsub(/\t#\n\tpap/,"yourNEwString")}7' file
如果你想让
sed
处理新行,你必须先读取整个文件:
sed ':a;N;$!ba;s/\t#\n\tpap/NewString/g' file
这可能对你有用(GNU sed):
sed '/^\t#$/{n;/^\tpap$/{p;s//\tpython/}}' file
如果一行仅包含
\t#
打印它,那么如果下一行仅包含 \tpap
也打印它,然后用 \tpython
替换该行并打印它。
一个 GNU
sed
解决方案,不需要立即读取整个文件:
sed '/^\t#$/ {n;/^\tpap$/a\\tpython'$'\n''}' file
/^\t#$/
匹配仅注释行(与 \t#
完全匹配),在这种情况下(仅)执行整个 {...}
表达式:
n
加载并打印 next 行。/^\tpap/
与下一行与 \tpap
完全匹配。a\\tpython
将在读取以下行之前输出
\n\tpython
- 请注意,需要拼接换行符($'\n'
)来表示传递给的文本结束a
命令(您也可以使用多个 -e
选项)。(顺便说一句:使用 BSD
sed
(OS X),它会变得很麻烦,因为
\n
和 \t
不直接支持,必须拼接为 ANSI C 引用文字。前导空格总是从
a
命令的文本参数中删除,因此必须使用替换方法: s//&\'$'\n\t'python'/
用自身替换 pap
行 plus 要附加的行:
sed '/^'$'\t''#$/ {n; /^'$'\t''pap$/ s//&\'$'\n\t'python'/;}' file
)
awk
解决方案(符合 POSIX 标准),也不需要立即读取整个文件:
awk '{print} /^\t#$/ {f=1;next} f && /^\tpap$/ {print "\tpython"} {f=0}' file
{print}
:打印每个输入行/^\t#$/ {f=1;next}
:如果找到仅注释行(与 f
完全匹配),则将标志 1
(表示“找到”)设置为 \t#
,并移至下一行。f && /^\tpap$/ {print "\tpython"}
:如果一行前面有注释行并且与 \tpap
完全匹配,则输出额外的行 \tpython
。{f=0}
:重置指示仅注释行的标志。您只需翻译该字符即可 到另一个,然后应用
sed
,然后应用反向翻译。例如,如果使用 tr
,则它必须是 1 字节字符(垂直制表,现在几乎未使用)。
cat FILE|tr '\n' '\v'|sed 's/\t#\v\tpap/&\v\tpython/'|tr '\v' '\n'|sponge FILE
或者,没有海绵:
cat FILE|tr '\n' '\v'|sed 's/\t#\v\tpap/&\v\tpython/'|tr '\v' '\n' >FILE.bak && mv FILE.bak FILE
几个纯粹的
bash
解决方案:
in=$'\t#\n\tpap\n' # input string
echo "${in/$'\t#\n\tpap\n'/$'\t#\n\tpap\n\tpython\n'}"
pap
之后是 \n
,而对 \t#
之前的内容没有做出任何假设,可能会导致误报。\t#\n\tpap
总是封闭在\n
中,echo "${in/$'\n\t#\n\tpap\n'/$'\n\t#\n\tpap\n\tpython\n'}"
将会稳健地工作;否则,请参阅下文。=~
运算符进行正则表达式匹配:=~
运算符支持右侧的扩展正则表达式,从而允许更灵活和稳健的匹配:
in=$'\t#\n\tpap' # input string
# Search string and string to append after.
search=$'\t#\n\tpap'
append=$'\n\tpython'
out=$in # Initialize output string to input string.
if [[ $in =~ ^(.*$'\n')?("$search")($'\n'.*)?$ ]]; then # perform regex matching
out=${out/$search/$search$append} # replace match with match + appendage
fi
echo "$out"