举例来说,我有一个file.txt
包含 3 行的内容:
hello
hello
hello
我有一个名为 的变量line=1
和一个变量 string substitute=hello1
。我想line
用名为 的新字符串变量替换变量描述的行中的字符串substitute
。
最终的更改将files.txt
如下所示:
hello1
hello
hello
我将如何使用sed
来做到这一点?或者awk
?如果这就是你想要的,只要我可以输入可以在 while 循环中更改的变量。
答案1
和perl
:
export line substitute
perl -pi -e '$_ = $ENV{substitute} . "\n" if $. == $ENV{line}' file.txt
与 GNU 相同awk
:
export line substitute
gawk -i /usr/share/awk/inplace.awk '
NR == ENVIRON["line"] {$0 = ENVIRON["substitute"]}
{print}' file.txt
在这里使用sed
并不理想,即使对于那些支持类似 perl-i
选项的选项也是如此,因为我们需要对它的值进行一些后处理,$substitute
如果它可能包含反斜杠、&
命令s
分隔符或换行符。看如何确保插入到“sed”替换中的字符串转义所有元字符详细信息。
在gawk
,不使用-i inplace
as尝试首先从当前工作目录gawk
加载inplace
扩展(asinplace
或),有人可能已经在其中植入了恶意软件。随系统提供的扩展inplace.awk
的路径可能会有所不同,请参阅输出inplace
gawk
gawk 'BEGIN{print ENVIRON["AWKPATH"]}'
答案2
假设line >0
并且总是整数,你可以这样做:
<infile head -n$(($line-1)); printf '%s\n' "$substitute"; tail -n +$(($line+1)) infile
请注意,如果 line_number > file's_number_of_lines,这会将$substitute
值附加到文件末尾$line
答案3
如果没有更多信息,以下awk
程序应该可以工作:
awk -v where="$line" -v what="$substitute" 'FNR==where {print what; next} 1' file.txt
- 它将把 shell 变量
$line
和导入$substitute
到awk
变量where
和中what
。 - 处理文件时,默认情况下它会简单地打印当前行(看似偏离
1
规则块之外的行{ ... }
)。 - 当每个文件的行计数器
FNR
等于存储在 中的行号时where
,我们将打印替换字符串what
,并跳到下一个输入行执行。
请注意,这awk
不会就地编辑文件,因此您必须在满意后重定向输出并重命名结果文件。或者,对于足够新的 GNU 版本awk
,您可以使用该-i inplace
选项就地修改文件。
笔记(正如 αГsнιη/Stéphane Chazelas/Ed Morton 所指出的)如果您的substitute
字符串包含文字,上面的代码将显示出不稳定的行为\
,因为此方法会扩展转义序列。在这种情况下,awk
Stéphane Chazelas 的答案中基于 - 的替代解决方案可以导出变量并引用它,这样就ENVIRON["substitute"]
可以解决问题(请参阅这个答案了解更多信息)。
答案4
$ line=1 substitute=hello1
$ sed -nf - <<eof file
$line r $(t=$(mktemp);printf '%s\n' "$substitute" > "$t";echo "$t")
$line!p
eof
我们使用heredoc来传递sed代码。 sed 代码正在读取文件并将 jts 内容放置在标准输出上,并通过该-n
选项抑制原始行。