是否有类似 tcsh 的 shopt glob 设置或设置组合?

是否有类似 tcsh 的 shopt glob 设置或设置组合?

我正在从长期的 tcsh 用户过渡到新的 bash 用户(已经太晚了)。我定期在 tcsh 中编写大量 foreach 循环,因此我学习了 bash 的 for 循环的语法作为替代,但当不匹配的 glob 模式作为文字字符串通过循环传递时,我感到惊讶。我寻找一种方法来改变这种行为,以便跳过并找到文字字符串shopt -s nullglob。我的理解是,理论上这应该等同于 tcsh 的行为方式,但今天我发现了一个差异。当我这样做时ls ../*.doesnotmatch,结果是当前目录内容的列表。具体来说,我是这样做的:

重击:

$ shopt -s nullglob
$ ls ../*.sam
extractSplitReads_BwaMem    extractSplitReads_BwaMem.xml
$ shopt -u nullglob
$ ls ../*.sam
ls: ../*.sam: No such file or directory

父目录中没有任何内容与 匹配*.sam,特别是当前目录。一开始我真的很困惑,但后来我意识到全局模式正在消失,并且命令正在执行,就好像我没有提供任何参数一样,例如:

$ ls

因此,我尝试单独设置failglob以及使用nullglob设置failglob,但只要设置了failglob,任何不匹配的glob模式都会终止该命令,无论是否存在匹配模式:

重击:

$ shopt -s failglob
$ shopt -s nullglob
$ ls ../vis*/*.xml
../visualization/LAJ.xml
$ ls ../vis*/*.xml ../*.sam
bash: no match: ../*.sam
$ ls ../{vis*/*.xml,*.sam}
bash: no match: ../*.sam

当我使用 tcsh 时,所有的 glob 都被归结为那些匹配的东西,如果没有匹配的东西,你会得到一个 glob 错误:

tcsh:

$ ls ../vis*/*.xml ../*.sam
../visualization/LAJ.xml
$ ls ../{vis*/*.xml,*.sam}
../visualization/LAJ.xml
$ ls ../*.sam
ls: No match.

我查看了 shopt 设置,但没有找到实现此行为的方法。我错过了什么吗?除了 bash 或 tcsh 之外,是否还有另一种现代 shell 可以像 tcsh 一样处理全局变量?我想要当有匹配的时候 nullglob 的行为,但是当没有匹配的时候failglob 的行为,这似乎是 tcsh 的工作方式。

答案1

shopt与文件名扩展相关的唯一选项是dotglobfailglob和,并且它们(单独或组合)似乎都不能完全满足您的要求。真遗憾,因为这听起来确实是个好主意。nocaseglobnullglob

我的建议是failglob在交互式会话中进行设置,这样您就可以避免可能不需要的命令,例如:

mv -r file1 file2 dir1 dir2 destination-*-dir

如果file1、和不匹配且已设置,file2则 和dir1将被移至其中。dir2destination-*-dirnullglob

另一方面,在 shell 脚本编写时完全依赖文件名扩展并不是一个好主意。建议始终验证此类扩展是否存在以及它们应该是什么。

我的意思是,不要这样做:

rm -- *.jpg *.txt

最好做这样的事情:

for file in *.jpg *.txt; do
  if [ -f "${file}" ]; then
    rm -- "${file}"
  fi
done

# Or this (non-POSIX, as it uses an array)

for file in *.jpg *.txt; do
  if [ -f "${file}" ]; then
    files_to_delete+=( "${file}" )
  fi
done

if [ "${#files_to_delete[@]}" -gt 0 ]; then
  rm -- "${files_to_delete[@]}"
fi

这样,即使某些文件匹配*.txt但它实际上是一个目录,您也会安全。

相关内容