![如何在使用 sed 命令时在模式中传递变量?](https://linux22.com/image/135327/%E5%A6%82%E4%BD%95%E5%9C%A8%E4%BD%BF%E7%94%A8%20sed%20%E5%91%BD%E4%BB%A4%E6%97%B6%E5%9C%A8%E6%A8%A1%E5%BC%8F%E4%B8%AD%E4%BC%A0%E9%80%92%E5%8F%98%E9%87%8F%EF%BC%9F.png)
我有文件abc.sh
search_dir='dummy'
filename='numbers.txt'
for entry in "$search_dir"/*
do
while read p;
do
sed -i '' "/$p/d" $entry
done < $filename
done
尝试删除具有匹配模式的行。基本上,模式只是我从文件传递的字符串。但不幸的是,它不起作用。
我能够调试的是,我没有以正确的模式传递变量。
编辑: 数字.txt
2018061300006178
2018061300006179
2018061300006325
2018061300006326
2018061400006505
search_dir 中存在的文件内容是:
1888~2018061400006505~0101~1~OWNED~SELF EMPLOYED~~~~3~~AGRICULTURE~~~OTHERS~AGRICULTURIST~~~AGRICULTURE~~~~~~~~N~N~Y~N~N~~300000-500000~~~49582E95361D5FA0C10C4C419B2940591C17E94EF329C31047A6B7DE26E68638
1889~2018061400006505~0101~2~OWNED~SELF EMPLOYED~~~~32~~AGRICULTURE~~~OTHERS~AGRIC
所以numbers.txt包含2018061400006505并且文件还包含数字相关数据,所以我想删除与给定数字匹配的行。
答案1
只要示例中的数字不包含sed
正在使用的分隔符(默认情况下/
),$p
代码中的 the 将被解释为正则表达式(及其所有含义)。
你的代码:
search_dir='dummy'
filename='numbers.txt'
for entry in "$search_dir"/*
do
while read p;
do
sed -i '' "/$p/d" $entry
done < $filename
done
在这里,您要删除下文件中$search_dir
包含 中任何数字的所有行$filename
。这是否有效取决于你的sed
对待方式-i ''
。对于某些实现,sed
您必须-i
在没有参数的情况下使用。
相关sed -i
和可移植性:如何使用 sed -i (就地编辑)实现可移植性?
将结果写入临时文件然后将该文件移动到原始文件名会更安全:
for entry in "$search_dir"/*
do
while read p;
do
sed "/$p/d" "$entry" >"$entry.tmp" && mv "$entry.tmp" "$entry"
done <"$filename"
done
这可以确保无论sed
您使用哪种实现,它都能正常工作。一般来说,在测试脚本时尝试对文件进行就地更改是一个坏主意,因此mv
在您对脚本的其他工作方式感到满意之前,您可能需要注释掉这一点。
尽管作为通用解决方案,这仍然有点不安全,因为您实际上是“使用数据作为代码”(数字是数据,并且您将它们用作sed
脚本的一部分)。这意味着您sed
只需/
在数字文件中的一个数字中插入 a ,就很容易在脚本中导致语法错误。
由于操作如此简单,我们可以改为使用grep
.这也摆脱了内部while
循环:
for entry in "$search_dir"/*
do
grep -Fv -f "$filename" "$entry" >"$entry.tmp" && mv "$entry.tmp" "$entry"
done
这将导致grep
从文件中读取其模式$filename
并将其应用到$entry
文件。-v
我们将丢弃任何包含模式的行,并且意味着-F
我们grep
将不是将数字解释为正则表达式,但解释为固定字符串。-f "$filename"
我们可以从grep
中读取字符串$filename
。
如果下面可能有目录,$search_dir
我们希望跳过这些:
for entry in "$search_dir"/*
do
[ ! -f "$entry" ] && continue
grep -Fv -f "$filename" "$entry" >"$entry.tmp" && mv "$entry.tmp" "$entry"
done
另一种更安全的操作方法是使用awk
.由于上面的sed
和grep
解决方案,数字是匹配的任何地方就行而言,可以想象我们可能会删除错误的行。可以awk
轻松匹配~
数据中的第二个 - 分隔字段:
for entry in "$search_dir"/*; do
[ ! -f "$entry" ] && continue
awk -F '~' 'NR==FNR { num[$0]; next } !($2 in num)' "$filename" "$entry" >"$entry.tmp" &&
mv "$entry.tmp" "$entry"
done
该awk
程序首先使用数字作为键填充关联数组/散列,然后打印$entry
文件中第二个~
- 分隔列不是该散列中的键的每一行。