因此,在bash大多数其他 shell 中执行此类操作将无法在子目录中创建多个子目录或文件...
mkdir */test
touch */hello.txt
Run Code Online (Sandbox Code Playgroud)
当然,实际上有很多方法可以做到这一点,我的首选方法是find在可能的情况下使用而不是使用for循环,主要是为了可读性。
但我的问题是,为什么上述方法不起作用?
据我所知,这是因为完整的目标文件/路径不存在,但如果我尝试使用mkdir或touch. 我一直只是继续前进,从未真正质疑过它。
但是有没有人对此有一个像样的解释来帮助我一劳永逸地理解?
您可能忽略的一点——很多人都遇到了问题,特别是如果他们在使用 *nix 之前有使用其他操作系统的经验时——是在许多其他操作系统中,命令行上的通配符通常会传递 给命令按照它认为合适的方式进行处理。例如,在 Windows 命令提示符中,
rename *.jpeg *.jpg
Run Code Online (Sandbox Code Playgroud)
而在 *nix 中,为了简化单个命令(例如,mv)的程序员的工作 ,通配符(未引用或转义时)由 shell 以独立于接口和通配符作为参数的命令的功能。称取文件名作为命令行参数的大多数程序期望这些文件存在(是的,mkdir和touch有例外这一规则,因为是mkfifo,mknod和,在部分程度上cp,ln,mv,和rename;还有可能是其他人),所以它shell 将通配符扩展为不存在的文件的名称并没有真正意义。对于外壳(而且,我的意思是每个 shell – Bourne、bash、csh、fish、ksh、zsh 等)以不同的方式处理异常可能会太麻烦。
也就是说,有几种方法可以获得您想要的结果。如果你知道通配符要扩展成什么,而且不长,你可以用大括号扩展生成它:
touch {red,orange,yellow,green,blue,indigo,violet}/rgb.txt
Run Code Online (Sandbox Code Playgroud)
更通用的解决方案:
sh -c 'for arg do mkdir -- "$arg"/test; done' -- *
Run Code Online (Sandbox Code Playgroud)
Gilles帮助我找到了另一种在 bash 中做到这一点的方法。
rename *.jpeg *.jpg
Run Code Online (Sandbox Code Playgroud)
显然benbradley这里只是一个标识符;您可以使用任何名称(例如,任何单个字母)。我花了几次尝试才做到这一点,所以让我分解一下:
identifier=value
创建一个名为identifier
(如果它不存在)的(标量)变量并将值分配value给它。例如,G=Man。您可以使用;来引用标量变量。例如,,或者更安全地,作为。例如,and可能未定义,但is和is 。$identifier$G${identifier}$Gage$Gilla${G}ageManage${G}illaManillaidentifier=(value1 value2 … )创建一个名为identifier
(如果它不存在)的数组变量并将列出的值分配给它。例如,光谱=(红橙黄绿蓝靛紫)或者
all_text_files=(*.txt)
$name将引用第一个元素(因此相当无用)。您可以将任意元素引用为; 例如,是
和是。您可以使用和
来引用整个数组。${name[subscript]}${spectrum[0]}red${spectrum[4]}blue${name[@]}${name[*]}
所以,这里是碎片:
" ${本布拉德利[@] / % //测试} "
${parameter/pattern/string}
扩展并替换with的最长匹配项。${parameter}patternstringpattern以 开头#,则它必须匹配 的扩展值的开头parameter。如果pattern以 开头%,则它必须匹配 的扩展值的末尾parameter。换句话说,% (the-rest_of_the_pattern)表现得像
(the-rest_of_the_regex) $(是的,这似乎有点倒退)。所以 a
pattern只是 a%
就像一个正则表达式只是 a $- 它匹配输入字符串的末尾(搜索空间)。
string的/test。所以这用/test
(即,它附加/test到参数)替换了参数的结尾。${parameter/pattern/string}}//stringstring/test/parameter是一个以@或*为下标的数组变量,则替换操作依次应用于数组的每个成员。${name[@]}${name[*]}