如何使shell识别`ls -A`命令返回的文件名,这些名称是否包含空格?

这是我用来重命名ls -A返回的文件的脚本的一部分:

 for FILE in `ls -A` do ext=${FILE##*.} NUM=$(($NUM+1)) NEWFILE=`echo $2_$NUM.$ext | sed 's/ /_/g'` mv "$FILE" "$NEWFILE" done 

但是找不到带空间的名字! $ 2参数不能成为错误的原因我为什么在没有空格作为参数的情况下执行名称,并且此脚本使用该名称并重命名文件夹中的所有文件,以便让它们编号并且不修改文件扩展名。 不幸的是,它不会重命名名称中带有空格的文件。 有人能帮我吗?

ls -A for me在一行上写了多个文件名,用空格分隔。 如果您尝试在ls -A1中添加-1 ,那么每行将输出一个文件名,并且可能更适合您。

我遇到了与文件名中的空格相同的问题,尤其是在使用find时,但是使用空字符分隔名称会处理文件名中的空格和换行符:
find (...) -print0 | xargs -0 (do stuff here)

但是,如果你只是想重命名文件,你可以考虑man rename它可以做以下事情:

 For example, to rename all files matching "*.bak" to strip the extension, you might say rename 's/\.bak$//' *.bak To translate uppercase names to lower, you'd use rename 'y/AZ/az/' * 

或者对于几个目录的gui解决方案,Thunar有一个很好的Rename Multiple Files接口,可以对你的描述进行编号。 我刚尝试了一些带空格的文件名,结合了Thunar的find,它似乎有效:
find . -type f -print0 | xargs -0 thunar -B

for 单词的迭代,单词由空格分隔。 你不应该迭代ls的输出,你应该使用* .*

 for file in * .* ; do if [[ $file = . || $file = .. ]] ; then continue fi # ... done 

您可以通过设置dotglob shell选项在bash’*’shell glob中包含隐藏文件(’dot files’)

 shopt -s dotglob for file in * do echo "$file" done 

例如,对于包含file的目录, file with spaces.hidden file (最后一个是隐藏的并且有空格),这会产生

 file file with spaces .hidden file 

您可能还想添加nullglob选项以防止在目录为空的情况下出现错误 – 请参阅优秀的BashFAQ / 004 。 请记住引用变量"$file"并且最好不要对变量名使用全部大写。

如果你还没想到,解析ls是一个坏主意 ® 。 除非你知道你的文件名永远是理智的(你通常不能),否则你需要能够处理包含以下内容的文件名:

  • 空格和制表符
  • 连续的空格或制表符
  • 换行符( \n
  • 回车( \r
  • 反斜杠( \

以上所有内容都是Linux内核允许的(并保证让您的系统管理员疯狂)。 以下两种方法可以处理上述任意组合。 我使用cp file directory/作为示例命令):

  1. 使用find及其-exec选项, {}将被找到的每个文件或目录替换。

     find . -exec cp {} directory/ 
  2. 管道查找结果为xargs为空分隔字符串( -print0 ),告诉xargs读取空分隔( -0 )并告诉它用每个文件/目录名称替换{}-I {} )。

     find . -print0 | xargs -0 -I {} cp {} directory/ 
  3. 单独使用shell,以匹配dotfiles,激活dotglob

      shopt -s dotglob for i in *; do cp -v "$i" directory/; done 
  4. 结合find的力量和shell的多function性

     find . -print0 | while IFS= read -r -d '' i; do cp "$i" directory/; done 

    IFS=禁用空格分割, -r禁用反斜杠转义(允许字面处理反斜杠),- -d ''将记录分隔符(如果你喜欢的行)设置为null。

怎么样:

 ls -A | while read fname do echo "$fname" # your code goes here done 

管道ls强制它每行发送1个文件名,然后read接受变量fname的行。