For 循环和定位命令正则表达式不匹配

For 循环和定位命令正则表达式不匹配

当我更改任何配置时,我会制作带有后缀 .original 的原始文件的副本。现在我正在编写一个简单的脚本,它将查找所有 *.original 文件并使用两个版本,即带或不带 .original 后缀。

我确实使用带有正则表达式的命令locate来避免文件与original路径中间的字符串不匹配。

我的命令是locate --regex ^.*\\.original$完美运行in terminal。它查找所有以 .original 后缀结尾的文件,例如file.original

然而in bash script当我在中使用相同的命令时,for loop它会返回诸如file.original file-original file_original等的变体。

我应该如何修改正则表达式或 for 循环以仅获取 .original 文件?

我的外壳是:

$ echo $BASH
/usr/bin/bash

我的 bash 脚本是:

#!/usr/bin/bash
echo "Plain locate command:"
locate --regex ^.*\\.original$ | grep test

echo "For loop:"
for file in `locate --regex ^.*\\.original$ | grep test`; do
        echo $file
done 

您可以使用它进行测试:

mkdir /tmp/test 
touch /tmp/test/file.original
touch /tmp/test/file-original
touch /tmp/test/file_original
updatedb
locate --regex ^.*\\.original$

在我的终端中它会发现:

/tmp/test/file.original

但我的脚本会发现:

Plain locate command:
/tmp/test/file.original
For loop:
/tmp/test/file-original
/tmp/test/file.original
/tmp/test/file_original

答案1

反引号需要更多转义。这是您应该更喜欢的原因之一$()(请参阅此答案中的“反斜杠乐趣”:$(stuff)和 和有什么区别`stuff`)。

由于反引号内没有足够的转义,当字符串最终被解释为正则表达式时,您想要转义的点不会被转义。

将相关行更改为:

for file in $(locate --regex '^.*\.original$' | grep test); do

笔记:

  • 我使用单引号来方便地处理反斜杠星号。在您的原始代码中,未加引号和未转义的星号可以触发文件名扩展

  • ^.*正则表达式中没有任何改变。单引号\.original$就足够了。我决定保留^.*只是为了指出文件名扩展的可能性。

  • 习惯于引用变量(例如echo "$file")。链接的答案$()也建议引用,但在我们的for循环中引用将是错误的。不引用$()也是错误的。两者都是错误的,因为……

  • 一般来说for像这样构建循环通常是错误的。这是Bash 的第一大陷阱。要对locatebetter 的输出执行某些操作xargs,最好将其作为以 null 结尾的字符串:

    locate -0 … | grep -z … | xargs -r0 …
    

    这些选项不可移植。

相关内容