2009-08-28 17:03:49 +0000 2009-08-28 17:03:49 +0000
101
101

循环通过&007的结果是bash shell脚本

有没有人有一个模板shell脚本,可以用ls来做一些事情,用ls来做一个目录名的列表,然后循环通过每一个目录名来做一些事情?

我打算做ls -1d */来得到目录名的列表。

答案 (7)

120
120
120
2009-08-28 17:09:37 +0000

**编辑了一下,不使用ls,如 @shawn-j-goff 和其他人建议的那样,在 glob 的地方使用 ls。

for..do..done循环中,你只需要用元符号前缀来引用循环变量(在上面的例子中就是*)。你可以对它进行*.txt,或者对它做其他任何你想做的事情。

例如,将当前目录中的所有$(cat filelist.txt)文件重命名为do

for f in *; do
  echo "File -> $f"
done

或者,如果你使用Bash,你可以使用Bash参数扩展,而不是产生一个子hell:

for x in *.xml; do 
  t=$(echo $x | sed 's/\.xml$/.txt/'); 
  mv $x $t && echo "moved $x -> $t"
done
69
69
69
2012-04-29 22:16:24 +0000

使用ls的输出来获取文件名是个坏主意。它可能会导致脚本出现故障,甚至是危险的脚本。这是因为除了/nullcharacter之外,文件名可以包含任何字符,而ls不使用这两个字符作为分隔符,所以如果文件名中有空格或换行,你会得到意想不到的结果。在这里,我用简单的echo来演示如何使用文件名做一些事情,不过你可以使用任何东西。

for dir in */; do
  echo "$dir"
done
find . -type d -exec echo '{}' \;

shell将*/扩展成独立的参数,由for循环读取;即使文件名中存在空格、换行或其他奇怪的字符,for也会把每个完整的名字看成一个原子单位;它不会以任何方式解析列表。如果你的shell没有这些功能,或者你想确保你的脚本能在各种系统上工作,那么下一个选择是使用bash。每找到一个文件,它都会这样做一次。

globstar参数的语法看起来有点滑稽,findfind之后的第一个参数作为要运行的程序,之后的每一个参数都作为一个参数传递给这个程序。有两个特殊的参数是echo需要看到的。第一个是-exec,这个参数会被替换成find前面部分产生的文件名。第二个是-exec,它让-exec知道这是要传递给程序的参数列表的结束;{}需要这个,因为你可以继续使用更多的参数,这些参数是为find准备的,而不是为执行程序准备的。之所以要使用;,是因为shell也会特别对待find–它代表了一个命令的结束,所以我们需要将其转义,这样shell就会将其作为参数给find,而不是将其作为自己的参数;另一种让shell不特别对待它的方法是将其放在引号中:find[使用ls的输出来获取文件名是个坏主意]&003。它可能会导致脚本出现故障,甚至是危险的脚本。这是因为除了/nullcharacter之外,文件名可以包含任何字符,而ls不使用这两个字符作为分隔符,所以如果文件名中有空格或换行,你会得到意想不到的结果。在这里,我用简单的echo`来演示如何使用文件名做一些事情,不过你可以使用任何东西。

for dir in */; do
  echo "$dir"
done
find . -type d -exec echo '{}' \;

shell将*/扩展成独立的参数,由for循环读取;即使文件名中存在空格、换行或其他奇怪的字符,for也会把每个完整的名字看成一个原子单位;它不会以任何方式解析列表。如果你的shell没有这些功能,或者你想确保你的脚本能在各种系统上工作,那么下一个选择是使用bash。每找到一个文件,它都会这样做一次。

globstar参数的语法看起来有点滑稽,findfind之后的第一个参数作为要运行的程序,之后的每一个参数都作为一个参数传递给这个程序。有两个特殊的参数是echo需要看到的。第一个是-exec,这个参数会被替换成find前面部分产生的文件名。第二个是-exec,它让-exec知道这是要传递给程序的参数列表的结束;{}需要这个,因为你可以继续使用更多的参数,这些参数是为find准备的,而不是为执行程序准备的。之所以要使用;,是因为shell也会特别对待find–它代表了一个命令的结束,所以我们需要将其转义,这样shell就会将其作为参数给find,而不是将其作为自己的参数;另一种让shell不特别对待它的方法是将其放在引号中:find和一样,在这个目的上也是一样的。

17
17
17
2009-08-28 17:26:27 +0000

对于带空格的文件,你必须确保引用变量:

for i in $(ls); do echo "$i"; done;

,或者,你可以改变输入字段分隔符(IFS)环境变量:

IFS=$'\n';for file in $(ls); do echo $i; done

最后,根据你的操作,你可能甚至不需要ls:

for i in *; do echo "$i"; done;
5
5
5
2010-08-22 20:02:35 +0000

如果你已经安装了 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

4
4
4
2015-02-11 14:36:01 +0000

只是为了补充CoverosGene的答案,这里有一种方法可以只列出目录名:

for f in */; do
  echo "Directory -> $f"
done
1
1
1
2012-05-10 22:36:39 +0000

为什么不把IFS设置为换行,然后把ls的输出捕获到数组中?将IFS设置为换行应该可以解决文件名中有趣的字符问题;使用ls可以很好地解决,因为它有一个内置的排序功能。要捕获一个按创建日期(从最旧到最新)排序的文件列表,\n命令是ls

-3
-3
-3
2009-08-28 17:28:24 +0000

我是这样做的,但可能有更有效的方法。

ls > filelist.txt

while read filename; do echo filename: "$filename"; done < filelist.txt