bash +如何验证特定路径下的文件夹是否以数字结尾

bash +如何验证特定路径下的文件夹是否以数字结尾

我想检查文件夹下/var/kafka所有文件夹都以数字结尾,否则我将错误退出

ls -ltr  /var/kafka
drwxr-xr-x 399 kafka kafka 28672 Nov  9 13:10 data6
drwxr-xr-x 392 kafka kafka 28672 Nov  9 13:10 data5
drwxr-xr-x 391 kafka kafka 28672 Nov  9 13:10 data1
drwxr-xr-x 405 kafka kafka 28672 Nov  9 13:10 data2
drwxr-xr-x 386 kafka kafka 28672 Nov  9 13:10 data4
drwxr-xr-x 389 kafka kafka 28672 Nov  9 13:10 data8
drwxr-xr-x 406 kafka kafka 28672 Nov  9 13:10 data7
drwxr-xr-x 397 kafka kafka 28672 Nov  9 13:10 data3

所以我创建了以下简单的代码(应该在 bash 脚本中)

for i in `  ls -ltr  /var/kafka | awk '{print $NF}' `; do  [[ ! $i  = *?[0-9] ]] && echo "ERROR folder/s not ended with number" && exit 1 ; done

但上面的例子代码太长,我想找到其他优雅的短命令来简单地验证下面的文件夹是否/var/kafka以数字结尾,

我们也可以使用awk/sed/Perl在内衬上。

答案1

zsh

files=( /var/kafka/*[^0-9](ND) )
if (( $#files )); then
  print -rlu2 -- "There are files whose name doesn't end in an ASCII digit:" ' - '$^files
  exit 1
fi

bash与:相同

shopt -s nullglob dotglob
shopt -u failglob
files=( /var/kafka/*[^0123456789] )
if (( ${#files[@]} )); then
  echo>&2 "There are files whose name doesn't end in an ASCII digit:"
  printf>&2 ' - %s\n' "${files[@]}"
  exit 1
fi

t要仅显示这些文件的基本名称/ ail(foo而不是/var/kafka/foo),请将和替换$^files为。$^files:t"${files[@]}""${files[@]##*/}"

请注意,严格来说*[^0-9](或*[^0123456789]在 bash 中)匹配以非数字字符结尾的文件名,对于不以数字结尾的文件名,^*[0-9]在 zsh 中(您需要)set -o extendedglob!(*[0-9])在 bash 中(您需要需要shopt -s extglob)但鉴于文件名不能为空,这应该是等效的。

如果您不需要在错误消息中列出这些文件,在 zsh 中,可以将其缩短为:

if () (( $# )) /var/kafka/*[^0-9](NDY1); then
  print -ru2 "There are files whose name doesn't end in an ASCII digit"
  exit 1
fi

其中Y1停止查看第一个匹配项,并将匹配列表传递给匿名函数,如果传递至少一个参数($#不为零),则该函数返回 true。

如果您只需要考虑类型的文件目录仍然在 zsh 中,添加/到 glob 限定符:

dirs=( /var/kafka/*[^0-9](ND/) )
if (( $#dirs )); then
  print -rlu2 -- "There are directories whose name doesn't end in an ASCII digit:" ' - '$^dirs
  exit 1
fi

bash 没有 glob 限定符,但您可以find报告名称不以数字结尾的目录类型文件:

使用 bash4.4 或更新版本并且find支持-print0

readarray -td '' dirs < <(
  cd /var/kafka &&
    LC_ALL=C find . ! -name . -prune -type d ! -name '*[0-9]' -print0
)
if (( ${#dirs[@]} )); then
  echo>&2 "There are dirs whose name doesn't end in an ASCII digit:"
  printf>&2 ' - %s\n' "${dirs[@]}"
  exit 1
fi

使用旧版本的 bash,您始终可以循环填充数组:

dirs=()
while IFS= read -rd '' dir; do
  dirs=("${dirs[@]}" "$dir")
done < <(
  cd /var/kafka &&
    LC_ALL=C find . ! -name . -prune -type d ! -name '*[0-9]' -print0
)

我们仅在 0123456789 上使用LC_ALL=Cso[0-9]匹配,而不是在其他语言环境中经常在 0 到 9 之间排序的数千个其他字符,并且还使0 或更多字符上的*in *[0-9]which 匹配 0 或更多字节。

现在请注意,某些语言环境使用的字符编码中除了 0123456789 之外还有一些其他字符,并且编码以与 0123456789 相同的字节值结尾。例如在中国使用的 GB18030 字符集中:

$ LC_ALL=zh_CN.gb18030 luit
$ locale charmap
GB18030
$ printf %s '¾' | LC_ALL=C od -tx1 -tc
0000000  81  30  86  36
        201   0 206   6
0000004

不管它是如何编码的,该¾字符通常都会被匹配,[0-9]因为出于明显的原因,它在 0 到 9 之间排序,而且,它的 GB18030 编码以字节 0x36 结尾,这恰好也是6ASCII 数字字符的编码。

因此,在 C 语言环境中,由 GB18030 编码组成的文件路径/var/kafka/¾¾¾将被视为以 ASCII 数字结尾,并且不会报告。是否应该是另一回事。

答案2

使用find

LC_ALL=C find /var/kafka -mindepth 1 -maxdepth 1 -type d -regex '.*[^0-9]$' | grep '^' \
&& echo "Error in folder name"

我正在“滥用”grep以获得合理的返回码,如果有人知道更好的方法,请告诉我。

答案3

另一种变体:

[ -z "$(LC_ALL=C find /var/kafka -mindepth 1 -maxdepth 1 -type d \( -name '*[0-9]' -o -print -quit \))" ]

$?如果所有目录名称都以数字结尾,则返回 true(为 0)

相关内容