有没有人使用模板外壳程序脚本来用ls做某事以获取目录名列表,并循环遍历每个人并做某事?

我打算做ls -1d */以获取目录名列表。

#1 楼

编辑后不要在@ globe-j-goff和其他人建议的地方使用ls。

只需使用for..do..done循环:

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


您可以将*替换为*.txt或其他任何返回列表(文件,目录或任何相关内容)的glob,该命令会生成一个列表,例如$(cat filelist.txt),或者实际上将其替换为列表。

do循环中,您只需引用带有美元符号前缀的循环变量(在上例中为$f)。您可以对其进行echo或对它进行任何其他操作。例如,将当前目录中的所有.xml文件重命名为.txt

甚至更好的是,如果您正在使用Bash,则可以使用Bash参数扩展而不是生成子shell:

for x in *.xml; do 
  t=$(echo $x | sed 's/\.xml$/.txt/'); 
  mv $x $t && echo "moved $x -> $t"
done


评论


如果文件名中有空格怎么办?

–丹尼尔·怀特(Daniel A. White)
09年8月28日在17:17

不幸的是,正如Daniel所说,如果任何文件或文件夹的名称中包含空格或换行符,则此答案中的代码将中断。它显示了一个非常常见的for循环滥用情况,以及尝试解析ls输出的典型陷阱。 @ DanielA.White,如果它对您没有帮助(或者可能会引起误解),那么您可能会考虑拒绝接受此答案,因为就像您说的那样,您正在对目录进行操作。 Shawn J. Goff的答案应为您的问题提供更可靠且有效的解决方案。

–slhck
13年1月23日在17:48

-∞您不应该解析ls输出,不应该在for循环中读取输出,您应该使用$()而不是``并使用More Quotes™。我敢肯定@CoverosGene的意思很好,但这太糟糕了。

–l0b0
2014年4月17日19:31



如果您真的想使用ls,一个更好的选择是ls -1 |边读边;做东西;完成。至少一个空格不会中断。

– ejoubaud
2014年8月1日在8:47

使用mv -v不需要回显“已移动$ x-> $ t”

–德米特里·桑达洛夫(DmitrySandalov)
16年1月15日,12:59

#2 楼

使用ls的输出获取文件名是一个坏主意。它可能会导致故障,甚至导致危险的脚本。这是因为文件名可以包含除/null字符以外的任何字符,并且ls不使用这些字符中的任何一个作为分隔符,因此,如果文件名包含空格或换行符,则会得到意外的结果。

有两种遍历文件的非常好的方法。在这里,我仅使用echo来演示如何使用文件名;但是,您可以使用任何东西。

第一个是使用Shell的本机全局功能。

for dir in */; do
  echo "$dir"
done


Shell将*/扩展为单独的参数for循环读取;即使文件名中包含空格,换行符或其他任何奇怪的字符,for也会将每个完整名称视为一个原子单位;

如果您想递归地进入子目录,那么除非您的shell具有一些扩展的globing功能(例如bashglobstar),否则您将无法执行此操作。 shell没有这些功能,或者如果要确保脚本可以在各种系统上运行,则下一个选择是使用find

find . -type d -exec echo '{}' \;


这里,find命令将调用echo并将其作为文件名的参数传递给它,它对找到的每个文件都执行一次,如上例所示,没有解析文件名列表;而是发送了一个文件名完全作为论点。

-exec参数的语法看起来有些滑稽。 find接受-exec之后的第一个参数,并将其作为要运行的程序,并将每个后续参数作为传递给该程序的参数。 -exec需要查看两个特殊参数。第一个是{};此参数将替换为find的先前部分生成的文件名。第二个是;,它使find知道这是传递给程序的参数列表的末尾。 find需要这样做,因为您可以继续使用更多的参数,这些参数是供find使用的,而不是供执行程序使用的。之所以使用\,是因为外壳程序还对;进行了特殊处理-它代表命令的结尾,因此我们需要对其进行转义,以便外壳程序将其作为find的自变量,而不是自己使用。使外壳不被特别对待的另一种方法是将其用引号引起来:';'\;一样好用。

评论


+1这绝对是您需要生成文件列表并在命令中使用它时要采用的方法。 find -exec只能通过运行单个命令来限制。通过循环,您可以充分利用自己的内心。

– MaQleod
2012年5月10日22:45

+1。我希望更多的人会使用find。可以做到的就是魔术,甚至可以解决-exec的局限性。 -print0选项对于与xargs一起使用也很有价值。

–ghoti
14-10-17在22:24

循环选项不会显示隐藏目录。查找选项不会显示符号链接。

– jinawee
19年5月21日在14:41

#3 楼

对于包含空格的文件,您必须确保引用以下变量:

 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;


评论


在第一个示例中很好地使用了子外壳

–Jeremy L
09年8月28日在18:46

为什么IFS在分配之后和新字符之前需要$?

– Andy Ibanez
2012年11月29日18:57

文件名也可以包含换行符。破坏\ n是不够的。建议解析ls的输出绝不是一个好主意。

–ghoti
2014-10-17 22:18



#4 楼

如果您已安装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

#5 楼

只需添加到CoverosGene的答案中,这是一种仅列出目录名称的方法:

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


#6 楼

为什么不将IFS设置为换行符,然后将ls的输出捕获到数组中?将IFS设置为换行符应该可以解决文件名中包含有趣字符的问题;使用ls会很不错,因为它具有内置的排序工具。

(在测试中,我无法将IFS设置为\n,但将其设置为换行退格键可以正常工作,如此处其他地方所述):

例如(假设在ls中传递了所需的搜索模式):

SAVEIFS=$IFS
IFS=$(echo -en "\n\b")

FILES=($(/bin/ls ""))

for AFILE in ${FILES[@]}
do
    ... do something with a file ...
done

IFS=$SAVEIFS


这在OS X上特别方便,例如,捕获按创建日期排序的文件列表(最早的最新),则ls命令为ls -t -U -r

评论


文件名也可以包含换行符,当允许用户命名自己的文件时,它们通常会包含换行符。破坏\ n是不够的。唯一有效的解决方案使用带有路径名扩展或查找的for循环。

–ghoti
14-10-17在22:21

传输文件名列表的唯一可靠方法是用NUL字符将它们分开,因为这绝对是文件路径中绝对没有的文件名。

– glglgl
2015年1月2日,9:23



#7 楼

在命令行中使用ls命令进行while循环

ls | while read filename;do echo "file name is $filename"; done


#8 楼

很好:
#!/bin/sh
for i in `ls`
do
   echo `ls -l $i`
done

这里是输出:
root@online:/usr/local/httpd/bin # more ~root/rm-in-ls.sh
    #!/bin/sh
    for i in `ls` 
    do
      echo `ls -l $i`
    done

root@online:/usr/local/httpd/bin # /root/rm-in-ls.sh
-rwxr-xr-x 1 root wheel 82516 Jul 3 04:52 ab
-rwxr-xr-x 1 root 40 3431 Jul 3 04:35 apachectl
-rwxr-xr-x 1 root 40 23881 Jul 3 04:35 apxs
-rwxr-xr-x 1 root wheel 21456 Jul 3 04:52 checkgid
-rwxr-xr-x 1 root 40 8931 Jul 3 04:35 dbmmanage
root@online:/usr/local/httpd/bin # 

没了!对!!!
要抬头!!!!!
在“ ls”中不是“'”! 。
'和`之间有区别。
我花了一个星期的时间来弄清我上大学的时间(1990年)。
这是“`”,带有〜的键Tilde主要是shift +〜,它被称为急性。wiki
如果没有得到,请复制并粘贴脚本并运行。

#9 楼

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

ls > filelist.txt

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


评论


坚持使用管道代替文件:> ls |一边读我回显文件名:$ i;做完了

–Jeremy L
09年8月28日在18:46

凉。我应该说,您也可以在两个命令之间使用$ EDITOR filelist.txt。您可以在编辑器中做很多事情,比在命令行上更容易。但是与此问题无关。

–树
09年8月31日在18:45

您的解决方案根本无法解决包含换行符和其他花哨的东西的文件名的问题。

– glglgl
2015年1月2日,9:24