如何在 bash 脚本中执行 rm -v !(*.yaml)?

Mar*_*ial 9 linux bash shell-script

脚本中写道:

rm -v !\(*.yaml\) ;\
Run Code Online (Sandbox Code Playgroud)

这会产生

rm: cannot remove '!(*.yaml)': No such file or directory
Run Code Online (Sandbox Code Playgroud)

但在命令行中工作正常。尝试过各种方式逃避:

rm -v !\(*.yaml\) ;\
Run Code Online (Sandbox Code Playgroud)

似乎无法找出适当的转义序列,我根本不明白。摆脱括号是我的第一步。然后试图逃跑!,然后*。还尝试使用反引号不转义,但出现错误“rm 缺少操作数”。我有点难住了。已经花了大约一个小时 - 只是“rm 所有内容而不是 yaml”...任何人都可以发现错误/建议修复吗?

我还尝试过#!/bin/sh 和#!/bin/bash。心想也许会有一些效果。

Sté*_*las 19

!(x)是一个 Korn shell 全局运算符。支持 的glob 运算符bash的子集,包括该运算符,但仅在\xc2\xb9之后kshshopt -s extglob

\n

所以:

\n
shopt -s extglob\nrm -f -- !(*.yaml)\n
Run Code Online (Sandbox Code Playgroud)\n

将删除当前目录中的所有非隐藏文件,除了名称以.yaml.

\n

无论如何,全局运算符在引用时不会被识别,因此使用\\(类似 Bourne 的 shell 中的引用运算符之一)不会有帮助。

\n

shell中的等价物zsh是:

\n
rm -f -- ^*.yaml\n
Run Code Online (Sandbox Code Playgroud)\n

为此,您需要set -o extendedglob.

\n

(它也支持or!(x)之后)。emulate kshset -o kshglob

\n

sh尽管您可能会发现某些sh实现,例如基于ksh支持!(x)作为扩展的实现,但该语言中没有等效的实现。

\n
\n

\xc2\xb9 由于它会影响 shell 语法解析,因此必须在读取和解析包含这些 ksh 扩展运算符之一的行之前shopt执行该命令。例如,在 中,您会收到语法错误,因为首先解析整行(extglob 尚未打开),然后运行(好吧,如果没有语法错误,就会运行)。很好。bash -c 'shopt -s extglob; echo !(x)'shoptbash -O extglob -c 'echo !(x)'

\n


Sot*_*oce 10

Bash 有一个功能,变量GLOBIGNORE可以告诉 shell 从 glob 中删除哪些文件名,而剩下的文件名则需要进行操作(在本例中为rm -v)。

这是一个演示:

mkdir /tmp/this-test
cd /tmp/this-test
touch one.yaml two.yaml three.json four.txt
echo *
Run Code Online (Sandbox Code Playgroud)

生产:

four.txt one.yaml three.json two.yaml
Run Code Online (Sandbox Code Playgroud)

现在设置GLOBIGNORE忽略.yaml文件,然后禁用它的效果:

GLOBIGNORE='*.yaml'
echo *
GLOBIGNORE=
echo *
Run Code Online (Sandbox Code Playgroud)

生产:

four.txt three.json
four.txt one.yaml three.json two.yaml
Run Code Online (Sandbox Code Playgroud)

rm -v *该命令echo *将删除目录中名称不以.yaml.

GLOBIGNORE可以有一个 glob 表达式列表,每个表达式用冒号 ( :) 分隔。例如,如果我 GLOBIGNORE='*.yaml:*.json' 在上面的演示中进行了设置,则该GLOBIGNORE值将从 glob 列表中删除 .yaml 和 .json 文件名,因此只会four.txt显示或删除该文件。