文件名中的空格有问题


8

我想对文件列表重复做一些事情。问题中的文件名称中带有空格:

david@david: ls -l
total 32
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha
-rw-rw-r-- 1 david david  0 Mai  8 11:55 haha~
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (3rd copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (4th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (5th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (6th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (7th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (another copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (copy)

现在,我要统计每个文件:

david@david: echo '
for file in $(ls)
do
stat $file
done' | bash

(我使用echo和管道来编写多行命令。)

当我这样做时,它可以正确处理名称中没有空格的那些文件。但是其他...

stat: cannot stat ‘(another’: No such file or directory
stat: cannot stat ‘copy)’: No such file or directory

更改$(ls)"$(ls)"$file"$file"不起作用。我能做什么?

编辑:

echo '
for files in *
do
stat "$files"
done' | bash

绝招!由于我是bash的新手,所以我想让事情尽可能简单-设法逃脱空间,或使用xargs或解决方案read -r,尽管它们解决了问题,但没有任何帮助。

正如一些人所问:是的,使用它代替stat *是很奇怪的。但是我只是想找到一种通用的方法,使用for循环在bash中的一堆文件名上应用相同的命令。因此stat可以代表gzipgpgrm


1
怎么了stat *?(;-)
Rmano


我仅以stat为例。:)我想用ls收集文件名,然后在bash循环中使用ls的结果。
user258532'5

Answers:


12

的多引号echo '使事情变得复杂。

您可以使用:

for f in *; do stat -- "$f"; done

但是也

stat -- * 

...如果要收集文件然后应用命令(为什么?),可以继续使用(但要小心包含新行的文件...(1))

for f in *; do echo "$f"; done | xargs stat --

...如果你想隐藏的文件太多,只使用* .*一个模式,但随后记得.,并..会在设定的

顺便说一句,您不应该解析lsoutput


(1)但是,如果您的文件名带有换行符,则应该得到它... ;-)


“然后应用命令(为什么?)”-> stat只能用作任意命令,因为我正在尝试如何使用文件名进行bash循环。可能是gpg,gzip或其他任何东西。
user258532'5

@ user258532无论使用什么命令,请始终使用for f in *; do command "$f"; done。从不解析ls,当然也绝不会for 循环执行,为什么要使用echo
terdon 2015年

echo:因为我喜欢在多行上写命令... :)
user258532'5

2
@ user258532嗯?你为什么需要回声?只需按Enter键,然后继续换行。如果您在行的末尾加上一个开放的引号,或者在,等等之一上do,则可以在新行上继续。要么使用heredocs。没有理由使用它也会引起问题。|&&echo
terdon

“只需按Enter并继续换行。” 哎哟。:-D现在我的智商正式低于0-你知道,我真的是bash之类的新手。但是我实际上是用R(统计套件和脚本语言)赚钱的。
user258532'5

6

附带说明:您可以通过在前面加上反斜杠并在Enter每次要开始写入新行的地方打一行来将长命令/复杂命令分成多行,而不是使用echo [...] | bash; 来分叉多个进程。另外,您还应该$file用双引号引起stat来,以防文件名包含空格时引起损坏:

for file in $(ls); \
do \
stat "$file"; \
done

问题是$(ls)扩展到包含空格的文件名列表,并且也会发生同样的情况"$(ls)"

即使解决了这个问题,该方法仍将在包含反斜杠的文件名和包含换行符的文件名(如terdon所指出的)上中断。

解决这两个问题的方法是将输出的管道find传递给while正在运行的循环,read -r以便在每次迭代时read -r将一行find的输出存储到$file

find . -maxdepth 1 -type f | while read -r file; do \
    stat "$file"; \
done

1
和隐藏文件?:)
AB

5
对于包含换行符的文件名,这仍将失败。只是不解析ls。曾经
terdon

4
@ user258532不,不是。说真的,只是不解析ls。有更好,更强大的方法。您可能还需要阅读以下内容:为什么*不*解析`ls`?更多细节。
terdon 2015年

1
这里的问题不是ls,而是for- for遍历关键字之后给出的(IFS分隔)单词in
glenn jackman 2015年

1
@glennjackman好吧,这是for和的组合lsfor f in *例如,会很好。
特登2015年

3

使用好old find,可以处理隐藏文件,换行符和空格。

find . -print0 | xargs -I {} -0 stat {}

或任何其他代替 stat

find . -print0 | xargs -I {} -0 file {}
find . -print0 | xargs -I {} -0 cat {}

1

作为R家伙,我已经在R中找到了解决方法:

filenames <- dir(); # reads file names into an array.
                    # It works also recursively
                    # with dir(recursive=TRUE)
for (i in 1:length(filenames)) {
system(     # calls a system function
 paste(     # join stat and the file name
  "stat",
  filenames[i]
 )
)
}

我知道,这很生气。我希望的输出ls将更易于解析... R可以处理空格,因为dir()返回带引号的字符值。引号之间的任何内容都是带空格的有效文件名。


3
不要打扰(但要努力+1!:)。只需使用for f in *,按Enter键并在新行上继续:dostat "$f"再次按doneEnter键,然后再按一次Enter键即可。这是一个很好地分割为4行的命令,不会中断任何类型的文件名。
terdon

1

我在for循环中遇到了空白问题的其他实例,因此通常使用以下(更强大的imo)命令。它也非常适合管道。

$ ls | while read line; do stat "$line"; done;

您可以将其与grep或组合使用find

$ find ./ -maxdepth 2 | grep '^\./[/a-z]+$' | while read line; do stat "$line"; done;

您的第一个答案对于包含反斜杠,前导或尾随空格的文件名失败。除非您将-E选项添加到中grep,否则您的第二个答案将完全失败,否则您将无法+在正则表达式中识别该选项。即便如此,由于您grep 删除了包含空格的文件名,因此在这个问题上还是摇摆不定。就像问题中的示例一样,它还会删除包含数字(数字)和标点符号(例如,括号)的文件名。甚至没有提到包含换行符或以-(破折号)开头的文件名。
斯科特,

-1

该答案将解决解析问题,ls并注意退格和换行

试试这个,它将使用内部字段分隔符IFS解决您的问题。

IFS="\n" for f in $(ls); do   stat "$f"; done

但是,您也可以轻松解决它,而无需使用以下命令解析ls输出

for f in *; do   stat "$f"; done

1
对隐藏文件不起作用。
AB

2
OP没有要求隐藏文件
Maythux

1
我看不到您为什么需要在IFS这里进行修改:引用变量应该足以防止单词分裂。
钢铁司机

用于解析ls
Maythux 2015年

到底是什么原因!!!
Maythux

-1

相反,您可以重命名文件,用其他字符(例如,下划线)替换空格,因此您可以摆脱此问题:

为此,请运行以下命令:

for file in * ; do mv "$f" "${f// /_}" ; done
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.