![Bash Shell 脚本通配符的噩梦](https://linux22.com/image/1561769/Bash%20Shell%20%E8%84%9A%E6%9C%AC%E9%80%9A%E9%85%8D%E7%AC%A6%E7%9A%84%E5%99%A9%E6%A2%A6.png)
我正在编写一个用于工作的 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