庆典SED无法在while循环 [英] bash sed fail in while loop

查看:154
本文介绍了庆典SED无法在while循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

#!/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循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆