Answers:
如@ shawn-j-goff和其他建议所建议,不要编辑在全局范围内使用ls。
只需使用一个for..do..done
循环:
for f in *; do
echo "File -> $f"
done
你可以替换*
使用*.txt
或(与此有关的文件,目录或其它)返回一个列表中的任何其他的水珠,生成一个列表中的命令,例如$(cat filelist.txt)
,或者实际上与列表替换它。
在do
循环内,您只需引用带有美元符号前缀的循环变量即可($f
在上面的示例中如此)。您可以执行echo
此操作,也可以执行其他任何操作。
例如,.xml
将当前目录中的所有文件重命名为.txt
:
for x in *.xml; do
t=$(echo $x | sed 's/\.xml$/.txt/');
mv $x $t && echo "moved $x -> $t"
done
甚至更好的是,如果您正在使用Bash,则可以使用Bash参数扩展而不是生成子shell:
for x in *.xml; do
t=${x%.xml}.txt
mv $x $t && echo "moved $x -> $t"
done
for
循环滥用,以及尝试解析的输出的典型陷阱ls
。@ DanielA.White,如果它对您没有帮助(或可能会引起误解),则可以考虑不接受此答案,因为就像您说的那样,您正在处理目录。Shawn J. Goff的答案应为您的问题提供更可靠且有效的解决方案。
ls
是ls -1 | while read line; do stuff; done
。至少一个空格不会中断。
mv -v
您不需要echo "moved $x -> $t"
使用of的输出ls
获取文件名不是一个好主意。它可能会导致故障,甚至导致危险的脚本。这是因为文件名可以包含除/
和以外的任何字符null
,并且ls
不使用这些字符中的任何一个作为分隔符,因此,如果文件名包含空格或换行符,则会得到意外的结果。
有两种遍历文件的非常好的方法。在这里,我只是简单echo
地演示了如何使用文件名进行操作;您可以使用任何东西。
第一种是使用Shell的本地Globing功能。
for dir in */; do
echo "$dir"
done
Shell扩展*/
为for
循环读取的单独参数。即使文件名中包含空格,换行符或其他任何奇怪的字符,for
也会将每个完整名称视为一个原子单位;它不会以任何方式解析列表。
如果你想递归进入子目录,那么这不会做,除非你的shell有一些扩展通配符功能(如bash
的globstar
。如果你的shell不具备这些功能,或者如果你想确保你的脚本将工作在各种系统上,那么下一个选择是使用find
。
find . -type d -exec echo '{}' \;
在此,该find
命令将调用echo
并传递文件名的参数。它为找到的每个文件执行一次此操作。与前面的示例一样,这里没有解析文件名列表。相反,文件名将完全作为参数发送。
该-exec
参数的语法看起来有些滑稽。find
接受第一个参数-exec
,并将其作为要运行的程序,并将每个后续参数作为传递给该程序的参数。有两个特殊的参数-exec
需要看。第一个是{}
; 此参数将替换为之前部分find
生成的文件名。第二个是;
,它让我们find
知道这是传递给程序的参数列表的末尾;find
之所以需find
要这样做,是因为您可以继续使用更多的参数,这些参数是针对执行程序的,而不是针对执行程序的。的原因\
是外壳程序也处理;
特别是-它代表命令的结尾,因此我们需要对其进行转义,以便外壳程序将其作为自变量find
而不是自己使用。使外壳不被特别对待的另一种方法是将其用引号引起来:';'
与\;
此目的一样有效。
find
。有魔术可以做到,甚至-exec
可以解决公认的局限性。该-print0
选项对于与结合使用也很有价值xargs
。
如果您安装了GNU Parallel http://www.gnu.org/software/parallel/,则可以执行以下操作:
ls | parallel echo {} is in this dir
要将所有.txt重命名为.xml:
ls *.txt | parallel mv {} {.}.xml
观看GNU Parallel的介绍性视频以了解更多信息:http : //www.youtube.com/watch?v=OpaiGYxkSuQ
为什么不将IFS设置为换行符,然后捕获ls
数组中的输出?将IFS设置为换行符应该可以解决文件名中包含有趣字符的问题;使用起来ls
很好,因为它具有内置的排序工具。
(在测试中,我无法将IFS设置为,\n
但是将其设置为换行符退格键即可,如此处其他地方所述):
例如(假设ls
传入了所需的搜索模式$1
):
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
FILES=($(/bin/ls "$1"))
for AFILE in ${FILES[@]}
do
... do something with a file ...
done
IFS=$SAVEIFS
这在OS X上特别方便,例如,要捕获按创建日期(从最旧到最新)排序的文件列表,ls
命令为ls -t -U -r
。
\n
不足。唯一有效的解决方案使用带路径名扩展的for循环或find
。
这就是我的方法,但是可能有更有效的方法。
ls > filelist.txt
while read filename; do echo filename: "$filename"; done < filelist.txt
ls | while read i; do echo filename: $i; done