【问题标题】:Bash syntax error in for loopfor循环中的Bash语法错误
【发布时间】:2015-04-17 21:04:04
【问题描述】:

我有一个类似“file1.stream_2015-02-17.mp4”的文件列表,我一直在使用它删除

#!/bin/bash

CONTENT_DIR=/my_files/recordings
find $CONTENT_DIR -mtime +1 -regextype posix-extended -regex '.*[.](mp4|tmp)$' -delete

到目前为止,这对我来说一直很好,但现在我试图在 1 天前删除所有带有 file1.stream 的文件,并在 7 天前删除所有带有 file2.stream 的文件

我一直在尝试这个,但我主要是不断地想出错误

#!/bin/bash
CONTENT_DIR=/my_files/recordings/*

for f in $CONTENT_DIR; do
  if [[ -f ${f} =~ 'file1.stream_*' ]] then
    find -mtime +7 ${f} -delete
  else
    find -mtime +1 ${f} -delete
  fi
done

但我不断收到此错误

syntax error in conditional expression 
syntax error near `=~'
`   if [[ -f ${f} =~ 'file1.stream_*' ]] then'

我不确定错误是什么,我已经四处寻找几个小时试图找到语法错​​误。感谢您的帮助

【问题讨论】:

    标签: bash if-statement for-loop syntax


    【解决方案1】:

    您似乎在污染两种不同的构造。您需要分别检查它们。

    [[ -f "$f" ]] 检查文件$f 是否存在并且是常规文件。

    [[ "$f" =~ regex ]] 检查$f 中的字符串是否与正则表达式regex 匹配。

    你可以这样组合它们:

    if [[ -f "$f" && "$f" =~ regex ]]; then ...
    

    或简单地将其分解为两个单独的比较:

    if [[ -f "$f" ]] && [[ "$f" =~ regex ]]; then ...
    

    还要注意then 之前所需的分号(或换行符)。

    但是您拥有的模式是 glob 模式,而不是正则表达式,因此您可能希望改用 glob 比较。

    此外,您的字符串不是find 的有效参数——我想您是真的意思

    if ...; then
        find -mtime +7 -name "$f" -delete
    : etc
    

    或者也许(在这种情况下有点等价)

    if ...; then
        find "$f" -mtime +7 -delete
    : etc
    

    其中参数肯定需要用双引号括起来,否则 shell 将对其执行通配符扩展并将变量替换为扩展结果,从而产生另一个语法错误。

    最后,将模式放在变量中然后不加引号地使用它并不是特别好的形式。该变量似乎没有任何用处,因此只需将模式内联到for 循环中即可。

    for f in /my_files/recordings/*; do
      if [[ -f "$f" && "$f" == 'file1.stream_'* ]]; then
        find -mtime +7 -name "$f" -delete
      else
        find -mtime +1 -name "$f" -delete
      fi
    done
    

    ...甚至只是决定条件内的mtime参数。

    for f in /my_files/recordings/*; do
      if [[ -f "$f" && "$f" == 'file1.stream_'* ]]; then
        mtime=+7
      else
        mtime=+1
      fi
      find -mtime "$mtime" -name "$f" -delete
    done
    

    【讨论】:

    • 我还没有仔细阅读这个问题,但不会:find /my_files/recordings \( -name '*file1.stream*' -mtime +7 -o -name '*file2.stream*' -mtime +1 \) -delete 就足够了吗?此外,正则表达式中的_* 非常无用,应该转义句点。
    • 谢谢,这真的很有帮助。我没有意识到我正在混合这两种结构,我查看了太多不同的 Q&A 并且把所有东西都混淆了。我不需要检查文件是否存在,所以我已经删除它并使用正则表达式
    • 实际上我完全赞同@gniourf_gniourf 的改进,即只运行一个find。它可能需要稍作更改(*file2.stream 占位符很可能需要适应您真正使用的文件名)但它要好得多。
    【解决方案2】:

    if 条件中有语法错误,=~ 仅用于正则表达式。

    你可以使用:

    #!/bin/bash
    
    for f in /my_files/recordings/*; do
      if [[ -f "$f" && "$f" == 'file1.stream_'* ]]; then
        find "$f" -mtime +7 -delete
      else
        find "$f" -mtime +1 -delete
      fi
    done
    

    glob 模式也需要在引号之外,如我上面的回答所示。

    【讨论】:

      【解决方案3】:

      你试图同时做两件事;检查文件 ($f) 是否存在并且是常规文件,并尝试将该测试的结果(这是返回码,而不是文本)与您给出的正则表达式(看起来也使用glob 而不是正则表达式模式匹配)。这里也不允许将两者结合起来。 then 是另一个(内置)命令,您需要将其与 if ... 部分分开。

      将检查拆分为应有的部分,并使用全局匹配或使用正则表达式,例如:

      if [[ -f "${f}" && "${f}" == file1.stream_* ]]; then ...; fi
      

      ...或者,对于正则表达式匹配:

      if [[ -f "${f}" && "${f}" =~ file1\.stream_.* ]]; then ...; fi
      

      另请注意,正则表达式匹配不会锚定到开头和结尾,因此与全局匹配不同,它实际上与 ^.*file1\.stream.*$ 相同。

      【讨论】:

      • 您的声明:不要引用匹配字符串,引号将包含在匹配项中,并且应该自己存在!完全错误。
      猜你喜欢
      • 1970-01-01
      • 2017-04-17
      • 2018-02-23
      • 1970-01-01
      • 2018-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多