重定向到变量有奇怪的行为

问题描述 投票:1回答:1

我有这个小脚本:

#!/bin/bash
for file in "$(ls | grep -v $0)";do
        cat $file > "${file}-test"
done

在这个目录上:

total 40
-rwxr-xr-x 1 root root   783 Dec 11 09:19 appendToLog.sh
-rwxr-xr-x 1 root root  3995 Dec 11 13:22 con2dd.py
-rwxr-xr-x 1 root root   362 Dec 11 13:26 dd.py
-rw-r--r-- 1 root root   566 Dec 11 13:26 dd.pyc
-rw-r--r-- 1 root root 18558 Dec 25 11:24 moshe.log
-rw------- 1 root root     0 Dec 11 09:20 nohup.out
-rwxr-xr-x 1 root root    88 Dec 25 11:28 task.sh
-rwxr-xr-x 1 root root   560 Dec 11 10:33 test.py

没关系,我可以通过cp实现这一点,我想知道为什么这正是产生这个文件:

-rw-r--r-- 1 root root 24912 Dec 25 11:28 appendToLog.sh?con2dd.py?dd.py?dd.pyc?moshe.log?nohup.out?task.sh?test.py-test

没有别的。

bash io
1个回答
2
投票

问题是解析ls的输出是错误的(参见Why you shouldn't parse the output of ls(1),unix中的文件名几乎可以包含任何特殊字符,包括空格,换行符,逗号,管道符号。因为你在一个结构中引用了ls的输出,你有一个所有文件的单个列表连接为"${file}-test"值中的一个字符串,这完全不是您想要做的。

还要注意ls有时会伪装你的文件名数据(在我们的例子中,它将单词之间的\n字符转换为?问号(可能表示无法显示的字符)。

只需使用bash中的glob扩展列出文件并对它们执行操作即可。

for f in *; do
    [[ -e $f ]] || continue
    ...
done

也就是说,你可能在行尾有一些不可打印的字符(例如CRLF导入的rom Windows)

运行cat -A scriptname它会显示脚本中的所有字符。然后,您可以转换为运行dos2unix scriptname的类似unix的格式。

© www.soinside.com 2019 - 2024. All rights reserved.