Bash Shell 脚本通配符的噩梦

Bash Shell 脚本通配符的噩梦

我正在编写一个用于工作的 shell 脚本,该脚本允许我根据我们系统使用的 5 位或 6 位数字查找目录,并从该目录中复制文件。我会手动执行此操作,但我需要从大约 3TB 的可用数据中获取 3000 多条记录。

这是我遇到的问题。我的脚本的一部分使用了 find,当我运行它时,脚本会在我放入脚本的通配符前面插入一个 '\r'。我尝试用 \ 对其进行转义,并将其括起来,但我所做的一切都不允许我在此命令中使用通配符。我在下面引用了我的代码。

#!/bin/bash

export IFS="\n"

cat $1 | while read -r LINE
do
    #Change directory to root of necessary files.
    cd /volume1/Backup/CMS_Data/CLIENT\ DATA\ COPY/

    echo "Current Directory"
    pwd

    #Get directory needed based on current line
    CLAIM="$(find $LINE\*/documents/ -type d)"

    #Change to directory based on claim number.
    echo $CLAIM

done

以下是我收到的结果。

find: `48668\r*/documents/': No such file or directory

我找不到任何有关 \r* 转义或如何解决它的信息。有什么想法导致它发生吗?

答案1

清除输入中的回车符的另一种方法是利用read命令的功能,从读取的内容中修剪前导和尾随空格。只需重新定义IFS(基本上是 shell 对空格的定义)以包含\r,如下所示:

... while IFS=$' \t\n\r' read -r LINE ...

请注意,由于的定义IFS是命令的前缀read,它仅适用于该命令,并且不会扰乱其他命令(或需要稍后恢复正常)。

顺便说一句,你对IFS开头的 的重新定义相当成问题,因为在那种特定情况下,反斜杠不被视为转义符,所以你实际上将\和定义n为了空格字符。这样可能会有真的奇怪的效果。我建议不要管它。

其他一些建议:cat读取文件;这毫无意义。只需重定向输入,如下所示:

while IFS=$' \t\n\r' read -r LINE
do
    ...
done <"$1"

此外,在变量引用周围加上双引号(就像我上面对 所做的那样$2)几乎总是一个好主意,以避免出现奇怪的解析伪像。 同样的事情也适用于$LINE。 哦,我还建议避免使用全大写的变量名; 其中很多都有特殊含义,很容易意外地重复使用其中一个并得到奇怪的结果。 使用小写或混合大小写的变量名要安全得多。

最后,我建议始终在脚本的命令中添加错误检查cd,因为如果检查失败,脚本的其余部分将在意外位置运行,并可能产生奇怪的结果。如下所示:

cd /volume1/Backup/CMS_Data/CLIENT\ DATA\ COPY/ || {
    echo "Error changing directory to CLIENT DATA COPY; giving up" >&2
    exit 1
}

答案2

您传递的文件$1\r\n换行符。您的$IFS\n,因此\r保留为 的最后一个字符$LINE

用于dos2unix转换文件。

答案3

似乎有多种方法可以解决这个问题。最简单的方法可能是修复 $LINE 变量以丢弃任何非数字字符。您可以通过在以 CLAIM= 开头的行之前添加以下行来实现此目的

  LINE=${LINE//[!0-9]//}

根据您的输入,您可能还需要将 CLAIM 行更改为 CLAIM="$(find $LINE/*/documents/ -type d)"

另一种解决方案是更改第一行以过滤掉输入中的回车符 - 您可以将其更改为类似

 tr -d "\r" < $1 | while read -r LINE

相关内容