【问题标题】:Bash script to list files not found用于列出未找到文件的 Bash 脚本
【发布时间】:2013-03-13 22:33:56
【问题描述】:

我一直在寻找一种方法来从需要存在的文件列表中列出不存在的文件。这些文件可以存在于多个位置。我现在拥有的:

#!/bin/bash
fileslist="$1"
while read fn
do
  if [ ! -f `find . -type f -name $fn ` ];
  then
   echo $fn
  fi
done < $fileslist

如果文件不存在,find 命令将不会打印任何内容,并且测试不会进行。删除 not 并创建 if then else 条件并不能解决问题。

如何打印从文件名列表中找不到的文件名?

新脚本:

#!/bin/bash
fileslist="$1"
foundfiles="~/tmp/tmp`date +%Y%m%d%H%M%S`.txt"
touch $foundfiles
while read fn
do
  `find . -type f -name $fn | sed 's:./.*/::' >> $foundfiles`
done < $fileslist
cat $fileslist $foundfiles | sort | uniq -u
rm $foundfiles

【问题讨论】:

  • 找出你能做的并与你期望的列表进行比较?
  • @cdeszaq,我想到的第一件事,但如果没有临时文件或纯粹的 bashisms 就想不出办法:)
  • 目前我创建了一个我可以找到的列表并与文件列表进行比较。我想我也许可以自动化这一些来创建我必须处理的文件列表。
  • 也许 find 不是正确的工具。有没有我没有想到的替代方案?
  • 我在家中在 Fedora 16 上测试了我的原始脚本,它似乎可以按照我的意愿工作。我在工作中使用 RHEL 5.7。这让我认为,发布的一些对我不起作用的答案可能对其他人有效。

标签: bash


【解决方案1】:
#!/bin/bash
fileslist="$1"
while read fn
do
  FPATH=`find . -type f -name $fn`
  if [ "$FPATH." = "." ]
  then
   echo $fn
  fi
done < $fileslist

你很接近!

【讨论】:

  • 这引发了一个问题,即 find 在找不到匹配项时返回什么。如何评估结果?
  • find 的退出代码在失败时将为 false。所以你可以简单地find . -name "$fn" &gt;/dev/null || echo Not there: "$fn"
【解决方案2】:

这里是 test.bash:

#!/bin/bash

fn=test.bash

exists=`find . -type f -name $fn`
if [ -n "$exists" ]
then
  echo Found it
fi

它将 $exists = 设置为查找的结果。 if -n 检查结果是否不为空。

【讨论】:

  • 如果 $exists 为空,那么你会在 'if' 语句中得到一个语法错误。
  • 我用一个存在的文件和一个不存在的文件测试了这段代码。效果很好。
  • -z 和 ! -n 与文件名不匹配时处理 find 的结果。
  • 抱歉,我把它弄反了。已编辑。
【解决方案3】:

尝试用[[ -z "$(find . -type f -name $fn)" ]] &amp;&amp; echo $fn 替换正文。 (请注意,这段代码在文件名中包含空格肯定会出现问题)。

更高效的 bashism:

diff <(sort $fileslist|uniq) <(find . -type f -printf %f\\n|sort|uniq)

我认为你可以处理差异输出。

【讨论】:

  • -z 和 ! -n 与文件名不匹配时处理 find 的结果。
  • 为我工作$ [[ -z "$(find /tmp -name nosuchfile)" ]] &amp;&amp; echo no such thing in there no such thing in there
  • 我添加了更有效的差异。由于您现在正在区分,我认为您可以正确调整 diff 选项并知道如何处理输出
【解决方案4】:

试试这个:

find -type f -print0 | grep -Fzxvf - requiredfiles.txt

-print0-z 防止文件名包含换行符。如果您的实用程序没有这些选项并且您的文件名不包含换行符,那么您应该没问题。

【讨论】:

  • 我喜欢这个想法,但我不认为 -v 选项可以这样工作
  • 使用 bash 循环和 grep -Fzqa 可以很好地工作。 10K 文件也很快
【解决方案5】:

重复find 一次过滤一个文件非常昂贵。如果您的文件列表与 find 的输出直接兼容,请运行单个 find 并从列表中删除任何匹配项:

find . -type f |
fgrep -vxf - "$1"

如果没有,也许您可​​以在fgrep 之前在管道中按摩find 的输出,使其与文件中的格式匹配;或者,相反,将文件中的数据按摩到find-compatible。

【讨论】:

  • 我正在查找 20 或 100 个文件,但我正在查找的目录结构有近 1500 个文件。我认为这行不通。
【解决方案6】:

我使用这个脚本,它对我有用

#!/bin/bash
fileslist="$1"
found="Found:"
notfound="Not found:"
len=`cat $1 | wc -l`
n=0;

while read fn
do
  # don't worry about this, i use it to display the file list progress
  n=$((n + 1))
  echo -en  "\rLooking $(echo "scale=0; $n * 100 / $len" | bc)% "
  if [ $(find / -name $fn | wc -l) -gt 0 ]
  then
    found=$(printf "$found\n\t$fn")
  else
    notfound=$(printf "$notfound\n\t$fn")
  fi
done < $fileslist

printf "\n$found\n$notfound\n"

该行计算行数,如果它大于 0,则查找成功。这会搜索硬盘上的所有内容。您可以将 / 替换为 .仅用于当前目录。

$(find / -name $fn | wc -l) -gt 0

然后我只需将文件列表中的文件用换行符分隔即可运行它

./search.sh files.list 

【讨论】:

    猜你喜欢
    • 2013-06-12
    • 1970-01-01
    • 1970-01-01
    • 2014-01-08
    • 1970-01-01
    • 2019-07-28
    • 1970-01-01
    • 1970-01-01
    • 2017-01-02
    相关资源
    最近更新 更多