在Bash脚本中,正则表达式会失效

编程语言 2026-07-09

我从一个zip文件中提取了一串字符串:

866275 2016-02-06 11:25 Documents/familystuff/Household/Agri Stuff/Sheep/sheep Photos/2014 ewe lambs/074Cleo 6Feb16a.jpg

我想要第一个字段(大小)和路径。

在一个在线正则表达式测试工具中测试时,这给出了我想要的结果:

(^[0-9]+)" "[0-9]{4}-[0-9]{2}-[0-9]{2}" "[0-9]{2}:[0-9]{2}" "(.+)

但当我把它放到脚本里时却没有输出

if [[ $x =~ (^[0-9]+)" "[0-9]{4}-[0-9]{2}-[0-9]{2}" "[0-9]{2}:[0-9]{2}" "(.+) ]]; then 
 echo bash0 Captured : ${BASH_REMATCH[0]}
 echo bash1 Captured number: ${BASH_REMATCH[1]}
 echo bash2 Captured NAME: ${BASH_REMATCH[2]}
fi

带有第一项:

if [[ $x =~ (^[0-9]+) ]]; then

它给出数字,但把其余任何部分加上后就没有输出

我需要改动什么才能让它工作?

解决方案

我把你原来的脚本放在 test.sh 里,在 GNU bash, version 5.2.21(1)-release (x86_64-pc-cygwin) 上按预期工作:

x='866275 2016-02-06 11:25 Documents/familystuff/Household/Agri Stuff/Sheep/sheep Photos/2014 ewe lambs/074Cleo 6Feb16a.jpg'
if [[ $x =~ (^[0-9]+)" "[0-9]{4}-[0-9]{2}-[0-9]{2}" "[0-9]{2}:[0-9]{2}" "(.+) ]]; then
 echo bash0 Captured : ${BASH_REMATCH[0]}
 echo bash1 Captured number: ${BASH_REMATCH[1]}
 echo bash2 Captured NAME: ${BASH_REMATCH[2]}
fi
$ bash test.sh
bash0 Captured : 866275 2016-02-06 11:25 Documents/familystuff/Household/Agri Stuff/Sheep/sheep Photos/2014 ewe lambs/074Cleo 6Feb16a.jpg
bash1 Captured number: 866275
bash2 Captured NAME: Documents/familystuff/Household/Agri Stuff/Sheep/sheep Photos/2014 ewe lambs/074Cleo 6Feb16a.jpg

为便于阅读,我建议把正则表达式放到一个变量里:

x='866275 2016-02-06 11:25 Documents/familystuff/Household/Agri Stuff/Sheep/sheep Photos/2014 ewe lambs/074Cleo 6Feb16a.jpg'
regex='(^[0-9]+) [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2} (.+)'
if [[ $x =~ $regex ]]; then
 echo bash0 Captured : ${BASH_REMATCH[0]}
 echo bash1 Captured number: ${BASH_REMATCH[1]}
 echo bash2 Captured NAME: ${BASH_REMATCH[2]}
fi

备选方案

看起来问题是在于 " "bash 中。

看起来它把第一个 " 视为 (^[0-9]+) 的结束,第二个 " 视为更长字符串的开头。

我找到了两种方法:

  1. 使用 \ 来转义空格,而不是 " "
x='866275 2016-02-06 11:25 Documents/familystuff/Household/Agri Stuff/Sheep/sheep Photos/2014 ewe lambs/074Cleo 6Feb16a.jpg'

if [[ $x =~ (^[0-9]+)\ [0-9]{4}-[0-9]{2}-[0-9]{2}\ [0-9]{2}:[0-9]{2}\ (.+) ]]; then 
 echo bash0 Captured : ${BASH_REMATCH[0]}
 echo bash1 Captured number: ${BASH_REMATCH[1]}
 echo bash2 Captured NAME: ${BASH_REMATCH[2]}
fi
  1. 把所有内容放在 ( ) 里,并使用普通空格而不是 " "
    但这需要在 BASH_REMATCH 中改变索引
x='866275 2016-02-06 11:25 Documents/familystuff/Household/Agri Stuff/Sheep/sheep Photos/2014 ewe lambs/074Cleo 6Feb16a.jpg'

if [[ $x =~ ((^[0-9]+) [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2} (.+)) ]]; then 
 echo bash0 Captured : ${BASH_REMATCH[0]}
 echo bash1 Captured number: ${BASH_REMATCH[2]}
 echo bash2 Captured NAME: ${BASH_REMATCH[3]}
fi

结果:

bash0 Captured : 866275 2016-02-06 11:25 Documents/familystuff/Household/Agri Stuff/Sheep/sheep Photos/2014 ewe lambs/074Cleo 6Feb16a.jpg
bash1 Captured number: 866275
bash2 Captured NAME: Documents/familystuff/Household/Agri Stuff/Sheep/sheep Photos/2014 ewe lambs/074Cleo 6Feb16a.jpg

在以下环境测试:GNU bash 5.2.21,Linux Mint 22(基于Ubuntu 24.04)


用于测试的完整代码:

#!/bin/bash 

x='866275 2016-02-06 11:25 Documents/familystuff/Household/Agri Stuff/Sheep/sheep Photos/2014 ewe lambs/074Cleo 6Feb16a.jpg'

echo '--- 1 ---'

if [[ $x =~ ((^[0-9]+) [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2} (.+)) ]]; then 
 echo bash0 Captured : ${BASH_REMATCH[0]}
 echo bash1 Captured : ${BASH_REMATCH[1]}
 echo bash2 Captured number: ${BASH_REMATCH[2]}
 echo bash3 Captured NAME: ${BASH_REMATCH[3]}
fi

echo '--- 2 ---'

if [[ $x =~ (^[0-9]+)\ [0-9]{4}-[0-9]{2}-[0-9]{2}\ [0-9]{2}:[0-9]{2}\ (.+) ]]; then 
 echo bash0 Captured : ${BASH_REMATCH[0]}
 echo bash1 Captured number: ${BASH_REMATCH[1]}
 echo bash2 Captured NAME: ${BASH_REMATCH[2]}
fi

我在其他Stack Overflow站点也发现了类似的问题

也许不完全是同一个问题,但也是寻找帮助的好去处

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章