我在掌握 Bash 脚本编写的基础知识时遇到了困难。这是我到目前为止所拥有的:
#!/bin/bash
FILES="/home/john/my directory/*.txt"
for f in "${FILES}"
do
echo "${f}"
done
我想做的就是.txt
在for
循环中列出所有文件,这样我就可以用它们做一些事情。但是 中的空格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 loop
或find command
将其设置IFS bash env variable
为:
IFS=$(echo -en "\n\b")