Bash 通配符不扩展

Bash 通配符不扩展

我正在尝试为目录中的每个文件创建一个目录。

mkdir *

返回文件存在。所以我尝试

mkdir *.d

它创建一个名为“*.d”的目录。如何强制扩展通配符?

答案1

通配符总是扩展为现存的名称。

您的命令mkdir *失败,因为扩展的名称*已存在。

您的命令mkdir *.d“失败”,因为它*.d与任何现有名称都不匹配。因此,默认情况下该模式不会展开1*.d并创建一个名为 的目录。您可以使用 删除它rmdir '*.d'

为每个目录创建一个目录常规文件在当前目录中,以便新目录与文件具有相同的名称,但带有后缀.d

for name in ./*; do
    if [ -f "$name" ]; then
        # this is a regular file (or a symlink to one), create directory
        mkdir "$name.d"
    fi
done

或者,对于喜欢“俏皮话”的人来说,

for n in ./*; do [ -f "$n" ] && mkdir "$n.d"; done

在 中bash,你也可以这样做

names=( ./* )
mkdir "${names[@]/%/.d}"

但这不会检查 glob 扩展为的内容是常规文件还是其他文件。

上述命令中的首字母./是为了防止文件名-中包含首字母破折号 ( ) 的文件名。否则,破折号及其后面的字符将被解释为 的选项mkdir


1 某些 shell 具有一个nullglobshell 选项,该选项会导致不匹配的 shell 通配符扩展为空字符串。在bash此启用使用shopt -s nullglob

答案2

for foo in bar; do baz; done我建议的不是解决方案:

find . -maxdepth 1 -type f -print0|xargs -0 -I file mkdir file.d

答案3

*.d扩展到名称以.d.

有了zsh,你可以这样做:

files=(*)
mkdir -- $^files.d

或者使用匿名函数:

() { mkdir -- $^argv.d; } *

或者通过 glob 限定符添加后缀e

mkdir -- *(e{REPLY+=.d})

或者:s应用于 glob 的历史修饰符(使用histsubstpatternfor%表示结尾):

set -o histsubstpattern
mkdir -- *(:s/%/.d)

您可能还不想通过添加^-/glob 限定符来对已经是目录或目录符号链接的文件执行此操作:

files=(*(^-/))
mkdir -- $^files.d

(请注意,它zsh没有其他类似 Bourne 的 shell 的缺陷,其中不匹配的模式会按原样传递,因此如果当前目录中没有匹配的文件,mkdir *.d则不会创建目录,它将中止命令而是出现错误)*.d*.d

相关内容