bash for循环空格

时间:2020-01-09 10:37:21  来源:igfitidea点击:

在Unix或Linux操作系统上,使用bash for循环如何处理文件名中的空格?
以下代码会报错:

#!/bin/bash 
files=$(ls *.txt) 
dest="/nas/server/dest" 
for f in $files 
do 
cp "$f" $dest 
done 

如何在bash shell上解决此问题? 为演示起见,请如下创建文件。 cd到/tmp并使用mkdir命令创建一个名为test的目录文件:

cd /tmp/ 
mkdir test 
cd test 

创建一组文件:

echo "foo" > "This is a test.txt"
echo "bar" > "another       file     name   with  lots of   spaces   .txt"
date > "current date and time.txt"
ls -l /etc/*.conf > "My configuration files.lst"
echo "Eat in silence; work in silence." > quote.txt
echo "Eat in silence; work in silence." > quote.txt
echo "Pride is blinding" > "A Long File    Name   .      doc"

要列出目录内容,请使用ls命令,如下所示:

$ ls -l

输出示例:

total 48
-rw-r--r--  1 Hyman  wheel    18 Feb  4 16:01 A Long File    Name   .      doc
-rw-r--r--  1 Hyman  wheel  1092 Feb  4 15:54 My configuration files.lst
-rw-r--r--  1 Hyman  wheel     4 Feb  4 15:54 This is a test.txt
-rw-r--r--  1 Hyman  wheel     4 Feb  4 15:54 another       file     name   with  lots of   spaces   .txt
-rw-r--r--  1 Hyman  wheel    29 Feb  4 15:54 current date and time.txt
-rw-r--r--  1 Hyman  wheel    33 Feb  4 15:58 quote.txt

确认问题

尝试使用以下语法而不是ls命令在for或while循环中读取带空格的文件名:

语法

for f in *
do
  echo "$f"
done

输出示例:

A Long File    Name   .      doc
My configuration files.lst
This is a test.txt
another       file     name   with  lots of   spaces   .txt
current date and time.txt
quote.txt

让我们尝试使用bash for循环将文件复制到$dest目录:

#!/bin/bash
dest="/nas/path/to/dest"
################################################################
## Do not use ls command to read file names in shell for loop ##
################################################################
for f in *.txt
do
  # do something with  $f now #
  cp "$f" "$dest"
done

将命令行参数$@(位置参数)用双引号引起来

您也可以传递命令行参数。
以下是一个不好的例子:

#!/bin/bash
for f in $@
do
        echo "|$f|"
done

如下运行:

./script *.txt

输出示例:

|This|
|is|
|a|
|test.txt|
|another|
|file|
|name|
|with|
|lots|
|of|
|spaces|
|.txt|
|current|
|date|
|and|
|time.txt|
|quote.txt|

以下是在bash for loop中处理命令行args的正确方法:

#!/bin/bash
for f in "$@"
do
        echo "|$f|"
done

如下运行:

./script *.txt

输出示例:

|This is a test.txt|
|another       file     name   with  lots of   spaces   .txt|
|current date and time.txt|
|quote.txt|

while循环处理空格示例

find . | while read -r file
do
  echo "$file"
done

或更好:

find . -type f -print0 | xargs -I {} -0 echo "|{}|"

或者

find . -type f -print0 | xargs -I {} -0 cp "{}" /path/to/dest/

使用IFS的带空格的for循环示例

警告:避免使用$IFS变量,这被认为是不好的做法,但出于历史原因在此显示。
有关更多信息,请参见下面的讨论。

O=$IFS
IFS=$(echo -en "\n\b")
for f in *
do
  echo "$f"
done
IFS=$O

要处理作为命令行参数传递的所有文件:

#!/bin/bash
O=$IFS
IFS=$(echo -en "\n\b")
for f in "$@"
do
  echo "File: $f"
done
IFS=$O