BASH 报告文件不存在,但确实存在

BASH 报告文件不存在,但确实存在

我有一份 find 生成的文件列表。由于管理层的规划不周,我现在需要统计这些文件,但由于我们正在扫描几 TB 的数据,因此 find 命令需要几个小时才能完成。所以我的计划是使用脚本遍历文件列表,并根据我们已经找到的文件运行统计。问题是 BASH 不断报告脚本中的所有文件都不存在,但使用脚本外的文件执行任何命令(仅在终端上)都可以正常工作。

前任:

sh ~/temp.sh  | head -1
stat: ./2017\ Digital/redacted\ Projects-redacted-IP.idx: stat: No such file or directory

stat -x ./2017\ Digital/redacted\ Projects-redacted-IP.idx
  File: "./2017 Digital/redacted Projects-redacted-IP.idx"
  Size: 25165824     FileType: Regular File
  Mode: (0500/-r-x------)         Uid: (redacted)  Gid: (redacted)
Device: 47,12   Inode: 440520    Links: 1
Access: Wed Jul  5 17:24:48 2017
Modify: Wed Jul  5 17:24:48 2017
Change: Wed Jul  5 17:24:48 2017

i=0
IFS=$'\n'
for j in $(cat ~/files); do
    stat -x $j
done

这些是挂载到 OSX 中的 /Volumes/ 的 Windows 共享。无论我如何更改引号(双引号/单引号/无引号/等等),脚本都会不断报告所有文件都不存在。我还尝试了该脚本的 Python 版本:

from subprocess import call
f=open( "/Users/me/files", "r" )
for l in f:
    call(["stat","-x","/Volumes/"+l])

出现同样的错误。问题似乎与文件名中的空格直接相关。因为当对另一个文件进行硬编码时,没有空格,它就可以正常工作。我假设我需要对变量进行不同的引用?但我无论如何也想不出引用这些变量的正确方法才能让它工作。

答案1

问题是 ~/files 中列出的路径在空格(可能还有其他字符)之前包含转义符(反斜杠),并且这些转义符被视为文件名的一部分。通常,当您输入如下命令时:

stat -x ./2017\ Digital/redacted\ Projects-redacted-IP.idx

shell 的解析过程将反斜杠解释为空格是参数的一部分(而不是参数之间的分隔符),然后将其移除在将参数传递给 之前stat。因此, stat 实际上接收两个参数:-x./2017 Digital/redacted Projects-redacted-IP.idx

另一方面,当您从文件读取文件路径时,它永远不会经过解析和删除转义符的步骤,因此转义符将stat作为参数的一部分传递,并且它会查找名称中实际带有反斜杠的文件(但找不到它们)。

引用对此没有帮助。shell 会解析(并删除)转义符、引号等替换变量值,这样它就不会最终解释并删除它们的值中的转义符和引号。(好吧,除非你使用类似的东西eval,但不要这样做——它为新事物出错打开了许多机会。)

事实证明,有一种简单的方法可以进行转义解析并从文件内容中删除。在评论中,我建议从循环切换forwhile read循环并链接BashFAQ #1:如何逐行(和/或逐字段)读取文件(数据流、变量)?。如果你读过,它实际上建议使用while IFS= read -r,并说:

选项-r可防止read反斜杠解释(通常用作反斜杠换行符对,以继续多行或转义分隔符)。如果没有此选项,输入中任何未转义的反斜杠都将被丢弃。您几乎应该始终将选项-r 与 一起使用read

...除非你反斜杠会被解释并删除(“丢弃”),因此只需去掉-r。哦,然后将所有变量引用括在双引号中,以防止它在空格上被拆分(如果没有双引号,无论空格是否被转义,都会发生拆分):

#!/bin/bash

i=0
while IFS= read j; do
    stat -x "$j"
done <~/files

相关内容