无法将正确的文件移动到mvfiles

时间:2018-12-10 14:12:07

标签: linux bash shell linux-kernel sh

我正在尝试grep多个文件中的定界符(逗号,管道或分号)。

如果文件包含任何这些定界符,则可以。我想将不包含任何这些定界符的文件移动到mvfiles目录中。即使文件中存在分隔符,该脚本当前仍在移动所有文件。

filename=$(find /opt/interfaces/sample_check -type f \( -name "*message.txt*" -or -name "*comma2*" -or -name "*comma3*" \))
pathname=/opt/interfaces/sample_check

echo $filename
echo $pathname

if `head -1 $filename | grep -o [';']`; then

    echo "Found"
else
    mv $filename /opt/interfaces/sample_check/mvfiles
fi

4 个答案:

答案 0 :(得分:2)

尝试稍微调整一下逻辑。另外,在grep模式中包含所有定界符,并调整其引号位置。

pathname=/opt/interfaces/sample_check
find "$pathname" -type f \( -name "*message.txt*" -or -name "*comma[23]*" \) |
  while read -r filename
  do if sed -n '1d; 2{ /[,;|]/q0 }; q1' "$filename"
     then echo "Delimited: $filename"
     else echo "Moving ==>> $filename"
          mv "$filename" /opt/interfaces/sample_check/mvfiles/
     fi
  done

由于我们只想基于文件第2行中的定界符来进行决定,所以我们改用sed

sed -n '1d; 2{/[,;|]/q0 }; q1' 

sed -n说什么都不打印,除非有要求-我们不需要任何输出。

1d删除第一行(我们不进行编辑,只是放弃了对该行的任何进一步处理,因此跳过了程序的其余部分。)

2{...}说仅在第2行执行这些命令。/[,;|]/q0说如果该行有任何逗号,分号或竖线,则使用zeo退出代码退出以指示成功。

q1说,如果到达这里,请以退出代码1退出。

它们触发if的分支。 :)

答案 1 :(得分:1)

我会避免将所有文件名放在一个变量中,因为如果文件名包含空格,则会出现问题。相反,我建议逐行读取文件名

pathname=/opt/interfaces/sample_check
echo $pathname

find "$pathname" -type f \( -name "*message.txt*" -or -name "*comma2*" -or -name "*comma3*" \) | while read filename
do

    echo $filename

    if head -1 "$filename" | grep '[;]' >/dev/null; then

        echo "Found"
    else
        mv "$filename" "$pathname/mvfiles/."
    fi
done

肯定有更多解决方案。

您也可以在现代系统上使用grep -q '[;]'代替grep '[;]' >/dev/null,但是在旧系统上,选项-q可能无效。

注意:我使用.../mvfiles/.假设mvfiles是现有目录。这样可以避免在目录不存在的情况下覆盖或创建同名文件。另外,我使用引号来避免文件名包含空格的问题。

答案 2 :(得分:0)

尝试使用grep -L列出不匹配的文件。

find $pathname -type f \( -name "*message.txt*" -or -name "*comma2*" -or -name "*comma3*" \) | xargs egrep -L ";|,|\|" | xargs  -IX mv  X $pathname/mvfiles

在上面的示例中,由于管道的OR条件,我使用egrep。也就是说,我们要指定多个正则表达式进行匹配。如果文件包含以下任何内容: ,| ,egrep将不会输出文件名。这仅将不匹配的文件传递给xargs。在Mac版本的xargs中,可以使用-I参数指定替换字符串。对于egreg输出的每个文件名,xargs将调用mv <文件名> $ pathname / mvfiles。

作为后续问题的一部分,有人问我如何仅查看文件的第二行。这里有一些代码可以做到这一点:

awk ' FNR == 2 && /[;|,]/ { print FILENAME } ' * 

当文件记录号(FNR)为2(每个文件的第二行)并且输入字符串与正则表达式[; |,]匹配时,上述awk将显示当前文件名(FILENAME)。

要在我上面的答案中插入这段代码,可以执行以下操作:

find $pathname -type f \( -name "*message.txt*" -or -name "*comma2*" -or -name "*comma3*" \) | xargs awk ' FNR == 2 && /[;|,]/ { print FILENAME } '   | xargs  -IX mv  X $pathname/mvfiles

因此,在上面,我用“ xargs awk”替换了“ xargs egrep”。另外,我从awk命令的末尾删除了*,因为这基本上是xargs的默认功能-接受stdin上的所有输入并将其作为命令的输入(在本例中为awk)提供。

由于我们使用的是awk,因此实际上可以避免最后一次使用xargs来移动文件。相反,我们可以构建命令并将其通过管道传输到bash(或某些shell)。

这是我们将命令传递到bash的版本:

find $pathname -type f \( -name "*message.txt*" -or -name "*comma2*" -or -name "*comma3*" \) | xargs awk ' FNR == 2 && /[;|,]/ { print "mv " FILENAME  " '$pathname'/mvfiles" } '   | bash

如果只想调试上面的语句而不采取任何措施,则可以在最后删除bash命令以保留此调试版本:

调试版本(不移动文件-仅显示mv命令):

find $pathname -type f \( -name "*message.txt*" -or -name "*comma2*" -or -name "*comma3*" \) | xargs awk ' FNR == 2 && /[;|,]/ { print "mv " FILENAME  " '$pathname'/mvfiles" } '  

答案 3 :(得分:-1)

据我了解,您想遍历与搜索匹配的文件名列表,然后检查其内容以查看其是否包含竖线,逗号或分号。如果是这种情况,您可以使用它。

# pathname is your directory you want files to search in
pathname=/opt/interfaces/sample_check

# here you can add different filenames that you want to match. I.e. only take files in the loop which contain filename1 in the name, or starts with filename2, or starts with filename3.
find $pathname -type f \( -name "*filename1*" -or -name "filename2*" -or -name "filename3*" \) -print0 |
while IFS= read -r -d '' file; do
    if grep -e '[|;,]' "$file"
      then
        echo "Found in $file."
    else
        echo "Not found in $file. Moving to directory xxx."
        mv "$file" /opt/interfaces/sample_check/mvfiles
    fi
done