问题描述
#!/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
大家好,我是新来的抨击。
Hi all, i am new to bash.
我有两个列出一个比另一个更旧。我希望在名字上FNAME反对RNAME进行比较。 结果是标准的放出来,如果它的名字是'RNAME仍然可用,我会搞定。如果不是,那么我会得到非零输出。
使用SED删除该行并重新路由到一个新的文件。
i have two lists one older than another. I wish to compare the names on 'fname' against 'rname'. 'Result' is the standard out put which i will get if the name is still available in 'rname'. if is not then i will get the non-zero output.Using sed to delete that line and re route it to a new file.
我已经由code的一部分尝试一部分,它的作品,直到我在while循环功能补充。 SED不似乎'newkas'的最终输出的工作是相同的初始输入'FNAME'。
是我错了方法还是我错过了任何零件?
I have tried part by part of the code and it works until i add in the while loop function. sed don't seems to work as the final output of 'newkas' is the same as the initial input 'fname'.Is my method wrong or did i miss out any parts?
推荐答案
您 SED
前pression不工作的原因是因为你使用单引号。你说
Part 1: What's wrong
The reason your sed
expression "doesn't work" is because you used single quotes. You said
sed '/$line/d' $fname > newkas
假设 FNAME = input.txt的
和行=示例文本
这将扩展为:
sed '/$line/d' input.txt > newkas
注意 $行
仍字面上present。这是因为庆典
不插单引号内的变量,从而 SED
看到 $
字面上。
Note that $line
is still literally present. This is because bash
will not interpolate variables inside single quotes, thus sed
sees the $
literally.
您可以说解决这个问题。
You could fix this by saying
sed "/$line/d/" $fname > newkas
由于双引号里面的变量将扩大。但是,如果你的 SED
前pression变得更加复杂,你可能会遇到的情况下难度在哪里,你打算成为跨$ P $的bash间$ P $点事通过 PTED的sed
。我倾向于使用形式
Because inside double quotes the variable will expand. However, if your sed
expression becomes more complicated you could run into difficulty in cases where bash interprets things which you intended to be interpreted by sed
. I tend to use the form
sed '/'"$line"'/d/' $fname > newkas
这是一个有点难以阅读,但是,如果你仔细看,单引号一切,我打算在 SED
前pression和双引号的一部分可变我想扩大。
Which is a bit harder to read but, if you look carefully, single-quotes everything I intend to be part of the sed
expression and double quotes the variable I want to expand.
您脚本包含了许多东西可以改进。
Your script contains a number things which could be improved.
echo "$(<$fname)" | while read line ; do
:
done
在第一个地方,你正在阅读的文件$(小于$ FNAME)
时,你可以只重定向而循环。这是一个有点多余,但更重要的是你要通过管道,而
,这将创建一个额外的子shell,并意味着你不能从封闭范围修改任何变量。不如说
In the first place you're reading the file with "$(<$fname)"
when you could just redirect the stdin of the while
loop. This is a bit redundant, but more importantly you're piping to while
, which creates an extra subshell and means you can't modify any variables from the enclosing scope. Better to say
while IFS= read -r line ; do
:
done < "$fname"
其次,考虑你的的grep
echo "$(<$rname)" | grep "$line"
同样,你正在阅读的文件,并呼应它使用grep。但是,的grep
可直接读取文件。
grep "$line" "$rname"
之后,你回声返回code和在如果
语句,这是一个的。
result=$( grep "$line" "$rname" ; echo $?)
相反,你可以只通的grep
直接如果
,这将考验其返回code
Instead you can just pass grep
directly to if
, which will test its return code.
if grep -q "$line" "$rname" ; then
sed "/$line/d" "$fname" > newkas
fi
在这里需要注意的是我所引述 $ FNAME
,如果它要永远包含一个空间,是非常重要的。我还添加了 -q
到的grep
,其中SUP presses它的输出。
Note here that I have quoted $fname
, which is important if it might ever contain a space. I have also added -q
to grep
, which suppresses its output.
现在有没有必要从如果
语句燮preSS的错误信息,在这里,因为我们不必担心包含一个不同寻常的价值$结果
或的grep
不返回正常。
There's now no need to suppress error messages from the if
statement, here, because we don't have to worry about $result
containing an unusual value or grep
not returning properly.
最终的结果是这样的脚本
The final result is this script
while IFS= read -r line ; do
if grep -q "$line" "$rname" ; then
sed "/$line/d" "$fname" > newkas
fi
done < "$fname"
这将无法工作,因为 newkas
将被覆盖在每个循环。这意味着,最终只在 $ FNAME
最后一行用。相反,你可以说:
Which will not work, because newkas
is overwritten on every loop. This means that in the end only the last line in $fname
was used. Instead you could say:
cp "$fname" newkas
while IFS= read -r line ; do
if grep -q "$line" "$rname" ; then
sed -i '' "/$line/d" newkas
fi
done < "$fname"
其中,我相信,会做你所期望的。
Which, I believe, will do what you expect.
但是,这是所有切解决您的实际问题。看来,我要简单地创建一个文件 newkas
包含除 $ FNAME
的所有行出现在 $ RNAME
。这是很容易与通讯
工具来完成的:
But this is all tangential to solving your actual problem. It appears to me that you want to simply create a file newkas
which contains the all the lines of $fname
except those that appear in $rname
. This is easily done with the comm
utility:
comm -2 -3 <(sort "$fname") <(sort "$rname") > newkas
这也改变了线路,这可能不利于你的排序顺序。如果你想做到这一点不改变顺序,然后使用@fge建议最好的方式。
This also changes the sort order of the lines, which may not be good for you. If you want to do it without changing the ordering then using the method @fge suggests is best.
grep -F -v -x -f "$rname" "$fname"
这篇关于庆典SED无法在while循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!