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


25

我无法了解Bash脚本编写的基础知识。这是我到目前为止的内容:

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

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

我要做的就是.txtfor循环中列出所有文件,以便我可以对它们进行处理。但是中的my directory星号和中的空格*.txt不能很好地播放。我试过使用带双引号和不带双引号,带或不带大括号的变量名,但仍然无法打印所有.txt文件。

这是非常基本的事情,但是我仍然在努力,因为我累了并且无法直截了当。

我究竟做错了什么?

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

Answers:


33

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

即使通配符确实扩展了,表达式"${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[@]}"是一个特殊情况:它将扩展为字符串列表,其中每个字符串都是文件名之一。带有空格或其他困难字符的文件名将得到正确处理。


1
伟大的作品
约翰·约翰·

值得注意的是,如果要通过函数传递这样的路径,则需要确保自己引用该变量而不是将其串联为较大字符串的一部分: for f in "$DIR"/*.txt= fine for f in "$DIR/*.txt"= breaks
pospi

7

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

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

#! /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

0

您可以做的是仅在引号之外保留通配符。
喜欢的东西:
一个在“与空格的文件” *“ TXT”

的处理
完成
。如果通配符本身扩展到空间,则需要T选用每行的办法文件,如使用ls -l命令生成的列表文件并使用bash read来获取每个文件。


-1

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

IFS=$(echo -en "\n\b")
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.