find and sed(查找并删除)

find and sed(查找并删除)

我有一个文件夹,里面有几个子文件夹和文件。还有一个 CSV 文件,其中包含子文件夹的名称以及子文件夹内文件中的模式。

我想要做的是使用主文件夹内的 while 循环读取 CSV 文件,并使用 删除匹配的模式文件sed。我bash在 Unix 中使用这个shell 脚本:

IFS=","
while read f1 f2
do
 find $f2/ -name vcs*.pv -exec sed -i '/$f1/d' {} +
done > export.csv

错误:

find: 'ap01\r/': No such file or directory.

CSV 文件:

S2AEC67X1,ap01

它正在f2正确读取值,但不执行其余操作。我将 CSV 文件保存在包含所有子文件夹的主目录中。

答案1

这:ap01\r

表明有一个回车在字符串之后api01。尝试从 CSV 文件中删除它。

更新:另请阅读@RomanPerekhrest 的评论。您需要将循环中的 更改>为 a (如果您确实应该这样做)<while使用一个while循环,但这完全是另一个讨论!)。

答案2

这个问题中的代码和输入文件存在一些问题:

  1. 输入文件的\r每一行显然都有尾随回车符 ( )。这可能是由于在 Windows 计算机上将 hit 创建为 DOS 文本文件。摆脱这些回车符的通常方法是dos2unix在文件上运行。例如,请参阅问题什么是“^M”以及如何摆脱它?

  2. 所有变量扩展都应该用双引号引起来。在您的命令中,您使用$f2不带引号的作为目录的路径名。如果$f2包含空格,这将失败。

  3. 单引号阻止 shell 扩展变量,这意味着您的sed脚本正在查找与文字正则表达式匹配的行$f1。这个正则表达式永远不会匹配,因为$只会匹配行尾,并且不会有行结束然后包含f1同一行上的字符。双引号sed编辑脚本将使 shell$f1在调用之前展开变量sed

  4. 该模式vcs*.pv应该是-name选项的参数find,但由于它未加引号,因此它将扩展到当前目录中与该通配模式匹配的任何名称。因此,如果当前目录中有一个名为 的文件vcs-test.pvfind将被调用-name vcs-test.pv,并且您只能找到具有该名称的文件。如果当前目录中有多个匹配的名称,您可能会find抱怨未知选项。

  5. 文件export.csv被输出到(并在循环发生任何输出之前清空)。您可能希望循环从中读取内容。这涉及更改><.

脚本已更正:

while IFS=',' read f1 f2; do
    find "$f2" -type f -name 'vcs*.pv' -exec sed -i "/$f1/d" {} +
done <export.csv

我还添加了-type ffind命令行,因为我们可能不想意外获取目录名称。我也这样做了,以便IFS设置变量仅有的read命令。


这是上述情况的变体,在所有文件都已定位的情况下直接地在您从 CSV 文件中读取其名称的顶级目录下方:

while IFS=',' read dir pattern; do
    for name in "$dir"/vcs*.pv; do
        test -f "$name" && sed -i "s/$pattern/d" "$name"
    done
done <export.csv

这样做的好处是你可以摆脱find。 坏处是现在sed每个文件都需要调用一次 (通常这不是问题,除非你有数百个或更多的文件)。

以下是上面的变体,根据以下内容删除行细绳从 CSV 文件中读取。不同之处在于,上面的代码片段将模式解释为正则表达式,不作为固定字符串。如果您的字符串包含在正则表达式中被解释为“特殊”的字符(例如.*、等),[则这一点很重要。]

while IFS=',' read dir string; do
    for name in "$dir"/vcs*.pv; do
        [ ! -f "$name" ] && continue
        grep -v -F -e "$string" "$name" >"$name.tmp" && mv -f "$name.tmp" "$name"
    done
done <export.csv

相关内容