使用ls $variable的Bash脚本

9

我试图让我的脚本列出所有形式为"$variable"的文件。

参数总是一个扩展名为.001的文件。 我想找到所有名称相同但扩展名不同的文件,例如$file.002, file.003等。例如:

first="$1"
others=${first%.001}
ls $others"*"

我的问题是文件名为file[success].mpg.001,但输入到ls中的是file[success].mpg*,导致出现ls: cannot access file[success].mpg*: No such file or directory错误。因为ls需要看到的是:
file\[success\].mpg*

我已经尝试了所有方法,唯一发现的是使用$1参数可以正常工作,但在file=$1之后使用$file就不行了。所以我想知道如何将变量更改为参数。

4个回答

10
你可以使用bash中的printf命令重新格式化字符串。另外,你不需要引用星号(*):

你可以使用bashprintf命令来重新格式化字符串。此外,您无需引用*

#!/bin/bash
first="$1"
others=$(printf %q "${first%.001}")
ls $others*

printf %q 会以一种可以用作shell输入的格式重新格式化字符串(参考 bash 的手册)。

编辑:根据评论:
上面的解决方案不能处理文件名中的空格。 对于这些情况(正如其他答案已经提到的),最好不要使用printf,而是正确引用所有变量:

#!/bin/bash
first="$1"
others="${first%.001}"
ls -- "$others"*

我很高兴能够帮助你。 - bmk
1
这适用于文件名中带有括号的文件,但不适用于其他奇怪字符,如空格。例如,我尝试了 ./findfiles1 "test [success].mpg.001",它将其解析为两个文件名,并且没有找到任何一个:ls: \[success\].mpg*: No such file or directory ls: test\: No such file or directory - Gordon Davisson
@Gordon:你说得对。这个方法不能处理空格/制表符的情况。对于这种情况,最好采用Philipp或Kaleb提到的解决方案,例如ls -- "${first%.001}"*。我会在我的答案中添加这个解决方案。 - bmk

5

您应该引用变量而不是通配符:

ls -- "$others"*

双破折号停止搜索选项,因此即使“others”以破折号开头,此代码也应该正常工作。
请注意,在脚本中,通常情况下使用“ls”都是错误的解决方案。仅在确实需要打印列表时才使用它,例如以长格式打印时:
ls -l -- "$others"*

如果你只想打印出文件名,那么完全不需要使用ls命令:

echo "$others"*

很遗憾,您不能在echo中使用--。 如果您想要一个文件名数组,请使用

filenames=("$others"*)

如果您想要遍历它们,请使用以下方法:

for filename in "$others"*

3
您说得不错。我的第一个修复方法是将第三行更改为以下内容:
ls -- "${others}".*

这将扩展$others并允许通配符匹配发生。这是shell的职责,将*扩展为所有匹配的文件名列表。然后将文件名列表发送给ls。在大多数情况下,ls将看到类似于以下内容:
file1.001 file1.002 file1.003 ...

但是,当没有文件存在时,shell会将通配符传递给ls命令,此时ls会看到星号(*):

file1.*

因此,您的命令行ls $others"*"会添加一个字面上的星号,这是ls所看到的。
除非您有一个名为file1.*(带有字面上的星号)的文件名,否则ls将失败。
另一种选择是使用basename:
first="$1"
others=`basename -- "$first" .001`
ls -- "${others}".*

使用basename的优点是它可以删除目录等内容。

然而,正如其他人所指出的那样,根据您对文件列表所做的操作,find可能更好。

编辑:双破折号不适用于所有*nix变体,但告诉lsbasename命令后面没有其他cli参数。引用您的变量可能是最佳实践,但我更喜欢简单地将它们省略,除非数据不可信。了解您的数据并适当引用。


你的变量没有正确地加引号,如果文件名包含空格或其他“特殊”字符,这会导致问题。使用 ls -- "$others"*basename -- "$first" 代替。 - Philipp

1

使用find代替ls:

$ ls weg.*
ls: weg.*: No such file or directory
$ find . -name weg.\*
$

查找命令“find . -name file[success].mpg*”没有找到任何内容。 - geekmagii
1
从l0b0的回答中,我猜我应该使用与ls不同的方法。 - geekmagii

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接