通过 shell 脚本查找隐藏和非隐藏文件

find hidden and non-hidden files via shell script

我写了一个小 shell 脚本,它在我的容器启动过程中创建了几个扩展名为 .dist 而没有扩展名的文件的副本。

#! /bin/sh

path=$(pwd)
echo $path
shopt -s dotglob
for file in ./*.dist; do

    filename=$(basename -- "$file")
    #echo $filename
    name="$path/${filename%.*}"
    #echo $name

    if [ -a "$name" ]; then
        echo "$name already exists."
    else
        echo "copy $file to $name"
        cp -f "$file" "$name";
    fi
done;
shopt -u dotglob

它在我的 MacO 上本地运行良好,但在容器中,Alpine 使用的不是 bash,而是 sh 作为 shell,它不知道 "shopt" 命令。

当您使用 bash 时,"shopt" 是我可以安装的东西还是只是一个可用的命令?

如果 shopt 不可用,我该如何更改我的脚本,让 for 循环查找隐藏文件(前面有点)以及普通文件?

示例,应该都可以找到: phpstan.neon.dist .php_cs.dist

POSIX shell specification has specific rules for Patterns Used for Filename Expansion,注意:

If a filename begins with a <period> ( '.' ) the <period> shall be explicitly matched by using a <period> as the first character of the pattern or immediately following a <slash> character. The leading <period> shall not be matched by [...] the <asterisk> or <question-mark> special characters.

GNUBashThe Shopt Builtin修改了这条规则:

dotglob: If set, Bash includes filenames beginning with a ‘.’ in the results of filename expansion. The filenames ‘.’ and ‘..’ must always be matched explicitly, even if dotglob is set.

所以 Bash-特定的 dotglob * 模式几乎像 POSIX * .*,除了一些特定的极端情况:POSIX .* 将匹配当前目录和父目录 ...,如果没有非隐藏文件名,那么您将得到一个文字* 在输出中。

您的 "files, possibly hidden that end in .dist" 规则与当前目录完全不匹配。您可以通过使用 test -f 仅处理已知存在的文件来防止 *.dist 不匹配,或者防止存在字面上名为 *.dist 的真实文件。

for file in *.dist .*.dist; do
  if test -f "$file"; then
    ...
  fi
done