#!/bin/bash
fname=$2
rname=$1
echo "$(<$fname)" | while read line ; do
result=`echo "$(<$rname)" | grep "$line"; echo $?`
if [ $result != 0 ]
then
sed '/$line/d' $fname > newkas
fi 2> /dev/null
done
大家好,我是bash的新手。
我有两个比另一个更老的列表。我希望将'fname'上的名字与'rname'进行比较。 '结果'是标准输出,如果名称仍然在'rname'中可用,我将获得。如果不是那么我将获得非零输出。 使用sed删除该行并将其重新路由到新文件。
我已经尝试了部分代码,直到我添加了while循环函数。 sed似乎不起作用,因为'newkas'的最终输出与初始输入'fname'相同。 我的方法错了还是错过了任何部分?
答案 0 :(得分:5)
sed
表达式“不起作用”的原因是因为您使用了单引号。你说
sed '/$line/d' $fname > newkas
假设fname=input.txt'
和line='example text'
这将扩展为:
sed '/$line/d' input.txt > newkas
请注意,$line
仍然存在。这是因为bash
不会在单引号内插入变量,因此sed
从字面上看$
。
你可以通过说
来解决这个问题sed "/$line/d/" $fname > newkas
因为在双引号内,变量将会扩展。但是,如果您的sed
表达式变得更复杂,那么在bash解释您打算由sed
解释的内容时,可能会遇到困难。我倾向于使用表格
sed '/'"$line"'/d/' $fname > newkas
这有点难以阅读但是,如果仔细观察,单引号我打算成为sed
表达式的一部分,并双引号我要扩展的变量。
您的脚本包含一些可以改进的内容。
echo "$(<$fname)" | while read line ; do
:
done
首先,当您可以重定向"$(<$fname)"
循环的标准输入时,您正在使用while
读取文件。这有点多余,但更重要的是,您正在使用while
,它会创建一个额外的子shell,这意味着您无法修改封闭范围内的任何变量。更好的说法
while IFS= read -r line ; do
:
done < "$fname"
接下来,请考虑您的grep
echo "$(<$rname)" | grep "$line"
你再次阅读文件并将其回显给grep。但是,grep
可以直接读取文件。
grep "$line" "$rname"
之后,您将回显返回代码,并在if
语句中检查其值,该语句为classic useless construct。
result=$( grep "$line" "$rname" ; echo $?)
相反,您可以直接将grep
传递给if
,if grep -q "$line" "$rname" ; then
sed "/$line/d" "$fname" > newkas
fi
将测试其返回码。
$fname
请注意,我引用了-q
,如果它可能包含空格,这很重要。我还将grep
添加到if
,这会抑制其输出。
此处无需取消$result
语句中的错误消息,因为我们不必担心grep
包含异常值或while IFS= read -r line ; do
if grep -q "$line" "$rname" ; then
sed "/$line/d" "$fname" > newkas
fi
done < "$fname"
无法正常返回。
最终结果是这个脚本
newkas
哪个不起作用,因为$fname
会在每个循环中被覆盖。这意味着最后只使用cp "$fname" newkas
while IFS= read -r line ; do
if grep -q "$line" "$rname" ; then
sed -i '' "/$line/d" newkas
fi
done < "$fname"
中的最后一行。相反,你可以说:
newkas
我认为,这会做你期望的事。
但这与解决您的实际问题完全相关。在我看来,您只想创建一个文件$fname
,其中包含$rname
的所有行,但comm
中显示的行除外。使用comm -2 -3 <(sort "$fname") <(sort "$rname") > newkas
实用程序
grep -F -v -x -f "$rname" "$fname"
这也会改变行的排序顺序,这可能对你不利。如果你想在不改变排序的情况下这样做,那么使用@fge建议的方法是最好的。
{{1}}
答案 1 :(得分:1)
如果我理解您的需要,您需要一个文件newaks
,其中包含$fname
中也在$rname
中的行。
如果这是你想要的,使用sed是过度的。使用fgrep
:
fgrep -x -f $fname $rname > newkas
此外,您的脚本存在问题:
grep
中捕获result
的输出,这意味着它永远不会完全为0;你想要的是执行命令,只需检查$?
echo
es是错综复杂的,只是grep whatever thefilename
或while...done <thefile
; $rname
中的正则表达式,这可能会产生意外结果。等等。