我正在尝试创建一个别名函数来从文件中删除输入的行:
function remove_line(){
line_to_remove="'s/^"$1"$//g'"
sed -i $(line_to_remove) my_file
}
例如:
remove_line domain.com
应该从给定文件中删除该域。
然而,似乎$
没有正确解释。我究竟做错了什么?
答案1
你的主要问题$(line_to_remove)
是命令替换,即用括号内的命令输出的文本替换的表达式(line_to_remove
我希望这会给您一个“命令未找到”错误)。您可能想使用"$line_to_remove"
它。
但是,将 shell 变量注入到sed
替换表达式中并不理想,因为它对注入的字符串设置了太多条件(它必须是有效的正则表达式并且不能包含/
等)
相反,我建议使用grep
并将结果写入标准输出或写入临时文件,在成功执行 后替换原始文件grep
,或者您可以让sponge
(来自 GNU moreutils 包)覆盖原始文件。
remove_lines () {
grep -v -Fx -e "$1" my_file | sponge my_file
}
此处使用的选项grep
确保作为函数的第一个参数给出的行按原样使用(而不是作为正则表达式),从头到尾匹配行,并从输入中删除匹配的行。
没有sponge
:
remove_lines () {
tmpfile=$(mktemp)
grep -v -Fx -e "$1" my_file >"$tmpfile" && mv "$tmpfile" my_file
rm -f "$tmpfile"
}
mv
仅当成功执行时才会执行,grep
如果rm -f
未成功执行则删除临时文件。
就我个人而言,我可能会这样编写函数:
remove_lines () {
grep -v -Fx -e "$1"
}
这允许用户像这样使用它:
remove_lines "my line" <my_file | sponge my_file
some-command | remove_lines "bumble bee" | other-command
这使得该函数充当过滤器只做罐头上所说的,即,它从输入中删除行,并且不关心输入来自何处或去向何处。