我有一个脚本,它在循环中使用 sed 来删除列表中包含单词的行:
for i in $list; do
sed -i "/$i/d" file
done
$list
从 SQL 查询创建:
list=$(psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC")
问题是我的公司最近实施了更严格的审计规则,其中包括所有fchown
或fchmod
系统调用。使用strace
,我看到每个都sed -i
包含一个fchown
和fchmod
系统调用。
对于一个大的列表变量,iowait
系统会急剧上升,而系统实际上会陷入困境,因为auditd正在向其日志写入大量的行。
我试图弄清楚是否有一种方法可以将列表变量在一行中传递给 sed ,以便文件仅打开和关闭一次。
我已经问过,对auditd规则的任何改变都是不可能的。
谢谢。
答案1
通过仅运行sed
一次并使用单个sed
脚本,而不是逐一调用无数的内联命令:
sedscript=$(mktemp)
for i in $list; do
echo "/$i/d" >> "$sedscript"
done
sed -f "$sedscript" -i /path/to/file
rm -f "$sedscript"
答案2
如果您可以仔细分配 中的单词list
,则可以使用 bash 参数扩展将每个空格替换为正则表达式替代器|
,然后要求grep
为您完成这项工作:
list='auditd the to'
cp file temp &&
grep -Ev "${list// /|}" temp > file &&
rm temp
答案3
如果你的 shell 支持数组,你可以这样做
mapfile -t arr < <(psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC")
将命令的输出放入 shell 数组中,然后
printf '/%s/d\n' "${arr[@]}" | sed -i.bak -f - somefile
将删除序列应用到somefile
, 适当的位置。如果从psql
命令返回的字段可能包含sed
.
这与 @DopeGhoti 的解决方案类似,只是它避免了临时脚本文件(并且应该处理表字段中的空格,如果有必要的话)。
答案4
如果这样:psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC"
给您一个以空格分隔的单词列表,请尝试以下操作:
$ psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC" \
| awk -v FS=" " -v OFS="|" '{$1=$1; print "("$0")"}' \
| xargs -I {} sed -i -E '/{}/d' file