我对此完全惊呆了。我正在运行每周脚本将日志文件移动到目录中。
mkdir 2022-04-30
mv *.* 2022-04-30/
当我这样做时 - 仅移动具有扩展名的文件,而不移动没有扩展名的文件。
如果我尝试*.
说找不到文件
如果我尝试*
它会执行我想要的操作,但它还会尝试将目录移动2022-04-30
到自身并打印错误。它不会影响脚本,但我想了解发生了什么。
我很确定*
意味着零个或多个字符。所以*.*
应该移动所有文件而不是目录。
发生了什么事以及如何制作一个脚本来执行我需要的操作而不移动目录?
CentOS 9 / bash
编辑:
文件名示例
2022-04-29abc.cde
2022-04-29 App
答案1
*
表示零个或多个字符
so*.*
表示一些字符,后跟一个点,后跟更多字符,so 将匹配foo.bar
, foo.
.bar
, foo.bar.baz
,但不匹配foobar
,因为中间的点与 中的任何内容都不匹配foobar
,这就是为什么它不移动没有扩展名的文件
*.
那么只会匹配foo.
,而不是foo.bar
,因为它只寻找以 a 结尾的东西.
要仅移动文件而不移动目录,您最好使用类似的东西find . -maxdepth 1 -type f
- 这会查找当前目录(.
)中的所有文件,而不是子目录中的文件(maxdepth
限制它,maxdepth 1
意味着仅指定的文件夹,maxdepth 2
将包含单层中的所有内容子文件夹等),-type f
仅过滤常规文件
find . -maxdepth 1 -type f -exec mv {} 2022-04-30/ \;
应该可以工作,尽管它不是纯 bash,因此可能无法移植到所有系统
-exec
for find 执行其后面的内容,{} 依次是命令的每个find
结果
(使用包含空格和换行符的文件名进行了简要测试)
(经过编辑以使用评论中的病态文件名)
答案2
*
表示零个或多个任意字符,.
表示单个字符点。所以*.*
意味着任何地方有一个(至少一个)点的名字。在类 Unix 上,点只是文件名中的常规字符,并且常规 glob 中的文件和目录之间没有区别。 (如果您只想匹配目录,可以使用*/
。)
在这里,看起来文件名包含字母,而目录不包含字母,因此为了瞄准这一点,您可以使用*[[:alpha:]]*
来匹配至少包含一个字母的名称。这仍然会匹配目录,但会避免像
2022-04-30
.
或者,如果您正在做的事情类似于mv 2022-04-29* 2022-04-29
(即将以日期开头的文件移动到匹配的目录),您可以使用
mv 2022-04-29?* 2022-04-29
精确匹配?
一个字符,因此?*
需要在日期后至少有一个字符。
在 zsh 中(但不是在 Bash 中),您可以用来*(.)
仅匹配常规文件(并且类似地*(/)
仅匹配目录)。在所有 shell 中,*/
仅匹配目录,但没有等效项仅匹配常规文件。 (略有不同的是,*/
名称是用尾部斜杠生成的。)