从bash路径数组中提取缺失的路径

从bash路径数组中提取缺失的路径

我有一系列的路径:

paths=(
  /foo/exists1
  /foo/exists2
  /foo/missing1
)

要找到丢失的内容:

ls "${paths[@]}" 1>/dev/null

演出:

ls:无法访问‘/foo/missing1’:没有此文件或目录

很好。现在我想清理一下:

ls "${paths[@]}" 1>/dev/null | sed 's/ls: cannot access //' | sed 's/: No such file or directory//''

但我明白:

ls:无法访问'/foo/missing1':没有这样的文件或目录
/foo/exists1
/foo/exists2

因此sed不起作用,并且现有文件也会显示出来。

为什么会发生这种情况(为什么它会忽略1>/dev/null),以及我该如何解决这个问题?

答案1

你已经已经发现代码没有按预期运行的直接原因是:错误ls被报告到 stderr(如POSIX 建议),它不会被管道捕获为输入。因此,您得到的是正常输出 (通过您的语句不变sed) 和 stderr (绕过它们) 的混合。我不知道为什么您的ls输出在调用之间发生了变化;将 stdout 重定向到 /dev/null 应该会从输出中删除所有“正常”(现有路径)。对此的修复是不是但是将 stderr 推送到 stdout。

如果你想要一个可靠的脚本,那么对输出进行后处理ls是一个危险的想法。关于这个主题的一篇好文章是“为什么你不应该解析 ls(1) 的输出”,可在 wooledge.org 网站上找到。Unix & Linux 网站上有一个深入的问答,涉及一些问题:为什么不是解析ls(以及该做什么)?。结果是 UNIX 文件名几乎可以包含任何字符,包括空格、制表符、换行符、单引号、双引号、转义单引号等!举几个简单的例子,考虑一下这些名称的目录,它们都是完全合法的:

  • “没有这样的文件” (mkdir "No such file"
  • “ls:无法访问‘foo’:没有那个文件或目录”(mkdir "ls: cannot access 'foo': No such file or directory"
  • “目录

    嵌入

    换行符”(mkdir $'directory\nwith\nembedded\newlines'

第一个目录是被错误捕获的(从 stdout 中)grep。第二个目录也是被错误捕获的,但随后被进一步破坏为完全不同的道路-- 可能存在也可能不存在! -- 语句sed。第三个是将 的输出传递ls到面向行的程序时发生的情况的一个例子;如果目录不存在,ls则会在多行上说明,这可能是您最终得到两个独立sed语句的原因!

为了区分“好路径”(存在且可读的路径)和“坏路径”,我建议循环遍历数组并为每个路径构建新数组。

for p in "${paths[@]}"
do
  if [ -r "$p" ]
  then
    goodpaths+=("$p")
  else
    badpaths+=("$p")
  fi
done

然后你可以对每一组做任何你想做的事情:

printf 'Good path: -->%s<--\n' "${goodpaths[@]}"
echo
printf 'Bad path: -->%s<--\n' "${badpaths[@]}"

答案2

问题显而易见......错误转到文件描述符 2,而不是标准输出。

因此必须重定向21然后 grep:

  paths=(
    /foo/exists1
    /foo/exists2
    /foo/missing1
  )
  ls "${paths[@]}" 2>&1 \
    | grep 'No such file' \
    | sed 's/ls: cannot access '\''//' \
    | sed 's/'\'': No such file or directory//'

相关内容