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

时间:2017-12-25 11:32:50

标签: bash io

我有这个小脚本:

#!/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

没有别的。

1 个答案:

答案 0 :(得分: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的格式。