Bash 脚本错误,字符串的路径包含空格和通配符

Bash 脚本错误,字符串的路径包含空格和通配符

我在掌握 Bash 脚本编写的基础知识时遇到了困难。这是我到目前为止所拥有的:

#!/bin/bash
FILES="/home/john/my directory/*.txt"

for f in "${FILES}"
do
  echo "${f}"
done

我想做的就是.txtfor循环中列出所有文件,这样我就可以用它们做一些事情。但是 中的空格my directory和 中的星号*.txt配合得不太好。我尝试在变量名称上使用带或不带双引号、带或不带花括号的它,但仍然无法打印所有.txt文件。

这是一个非常基本的事情,但我仍然很挣扎,因为我很累,无法正常思考。

我究竟做错了什么?

如果我的文件没有空格或星号,我已经能够成功应用上面的脚本...我必须尝试使用​​或不使用双引号和大括号才能使其正常工作。但是当我同时拥有空格和星号时,一切都会变得混乱。

答案1

在引号内,*不会扩展为文件列表。要成功使用此类通配符,它​​必须位于引号之外。

即使通配符确实扩展,表达式"${FILES}"也会生成单个字符串,而不是文件列表。

一种可行的方法是:

#!/bin/bash
DIR="/home/john/my directory/"
for f in "$DIR"/*.txt
do
  echo "${f}"
done

在上面,带有空格或其他困难字符的文件名将被正确处理。

更高级的方法可以使用 bash 数组:

#!/bin/bash
FILES=("/home/john/my directory/"*.txt)
for f in "${FILES[@]}"
do
  echo "${f}"
done

在本例中,FILES是文件名数组。定义周围的括号使其成为一个数组。请注意, 位于*引号之外。该构造"${FILES[@]}"是一种特殊情况:它将扩展为字符串列表,其中每个字符串都是文件名之一。带有空格或其他困难字符的文件名将被正确处理。

答案2

虽然使用 John1024 所示的数组更有意义,但在这里,您还可以使用 split+glob 运算符(不加引号的标量变量)。

由于您只需要该运算符的 glob 部分,因此需要禁用分裂部分:

#! /bin/sh -
# that also works in any sh, so you don't even need to have or use bash

file_pattern="/home/john/my directory/*.txt"
# all uppercase variables should be reserved for environment variables

IFS='' # disable splitting

for f in $file_pattern # here we're not quoting the variable so
                       # we're invoking the split+glob operator.
do
  printf '%s\n' "$f" # avoid the non-reliable, non-portable "echo"
done

答案3

您可以做的就是仅将通配符保留在引号之外。
类似于:
for a in "files with space"*".txt"
do
process
done
如果通配符本身扩展为空格,那么您将不需要使用每行一个文件的方法,例如使用 ls -l 生成以下列表文件并使用 bash read 来获取每个文件。

答案4

当您想要处理一组文件时,您会考虑,它们的名称可能是空格或其他 scape 代码,因此在开始处理之前,例如for loopfind command将其设置IFS bash env variable为:

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

相关内容