没有指定目的地的`.mv ./*`有什么作用?


Answers:


41

如果最后一个参数是目录,则只需将当前工作目录中的所有文件和目录(名称以点开头的文件和目录除外)都移到该目录中。如果有两个文件,则第一个文件可能已覆盖第二个文件。

这是一些示范:

超过两个文件,最后一个参数是一个文件

$ mkdir d1 d2 d3
$ touch a b c e
$ mv *
mv: target 'e' is not a directory

两个以上的文件,最后一个参数是目录

$ mkdir d1 d2 d3
$ touch a b c
$ mv -v *
'a' -> 'd3/a'
'b' -> 'd3/b'
'c' -> 'd3/c'
'd1' -> 'd3/d1'
'd2' -> 'd3/d2'

两个档案

$ touch a b
$ mv -v *
'a' -> 'b'

进一步说明

Shell将glob(*)扩展为的参数mv。球形通常按字母顺序扩展。mv总是看到文件和目录的列表。它永远不会看到这个球体本身。

该命令mv支持两种类型的移动。一个是mv file ... directory。另一个是mv old-file-name new-file-name(或mv old-file-name directory/new-file-name)。


30

首先,我将做一个测试基础-5个文件和一个文件夹:

touch file1 file2 file3 file4 file5
mkdir folder

接下来,我将运行一个测试命令。该-v选项指定我希望将shell执行的每个命令都打印到stderr。该-x选项指定我希望将相同的内容打印到stderr- 我希望评估命令之后外壳程序运行之前完成打印。

sh -cxv 'echo mv *'

输出值

echo mv *
+ echo mv file1 file2 file3 file4 file5 folder
mv file1 file2 file3 file4 file5 folder

因此,您看到我输入外壳程序echo mv *的命令是,并且在扩展外壳程序 执行的命令之后*echo mv所有这些文件和文件夹。

默认情况下,shell会扩展glob,例如:

sh -cxv 'echo file[1-5]'

输出值

echo file[1-5]
+ echo file1 file2 file3 file4 file5
file1 file2 file3 file4 file5

这是set [+-]fglob函数的结果:

sh -cxvf 'echo file[1-5]'

输出值

echo file[1-5]
+ echo 'file[1-5]'
file[1-5]

因此,当您在配置有默认选项mv *的shell中运行命令时,例如shell会将*单词扩展为单词,该列表将根据语言环境对当前目录中的所有文件进行排序。它的系统调用exec(ve)mv (基本上)与附加此参数列表。因此mv,当shell遍历它们并对它们进行排序时,将获取所有参数。除了strace查看这些效果之外,还可以像下面这样再次使用调试:

sh -s -- mv * <<\SCRIPT
sed -n l /proc/$$/cmdline
echo "$@"
SCRIPT

输出值

sh\000-s\000--\000mv\000file1\000file2\000file3\000file4\000file5\000folder\
\000$
mv file1 file2 file3 file4 file5 folder

并且可移植:

( PS4= IFS=/; set -x mv *; : "/$*/" ) 2>&1

输出值

: /mv/file1/file2/file3/file4/file5/folder/

基本上,shell mv将使用目录的内容(如果.目录不为空并且不包括名称以开头的文件/文件夹作为其参数列表执行。mv是POSIX规定来解释它的最后一个参数为一个目录如果有两个以上的参数调用-以同样的方式ln(因为,事实上,他们在基本功能令人难以置信的类似的工具)

echo尽管足够:

sh -cxv 'mv *' ; ls

输出值

mv *
+ mv file1 file2 file3 file4 file5 folder
folder/

所有文件都移到了最后一个参数中-因为它是一个文件夹。现在,如果它不是文件夹怎么办?

sh -cxv 'cd *; mv *'; ls . *

输出值

cd *; mv *
+ cd folder
+ mv file1 file2 file3 file4 file5
mv: target ‘file5’ is not a directory

.:
folder/

folder:
file1  file2  file3  file4  file5

这是POSIX指定的 mv在这种情况下的行为:

mv [-if] source_file target_file

mv [-if] source_file... target_dir

在第一个提要形式中,mv实用程序应将source_file操作数命名的文件移动到target_file指定的目标。当最终操作数未命名现有目录并且不是引用现有目录的符号链接时,将采用此第一摘要格式。在这种情况下,如果source_file命名为非目录文件,而target_file以结尾/slash字符结尾,mv则应将此视为错误,并且不会处理任何source_file操作数。

在第二个摘要表中,mv应将由source_file操作数命名的每个文件移动到由target_dir操作数命名的现有目录中的目标文件,如果target_dir是引用现有目录的符号链接,则应引用该文件。每个source_file的目标路径应为目标目录的串联;/slash如果目标未以a结尾,则为单个字符/slash;以及source_file的最后一个路径名部分。当最终操作数命名现有目录时,采用第二种形式。

因此,如果*扩展为:

  • 两个文件

    • 您应该只有一个文件,renamed第二个文件是,第一个文件到第二个文件unlinked
  • 一个或多个文件,后跟一个目录或一个链接

    • 您应该只有一个目录或一个指向目录的链接,在该目录中,其父目录的所有先前内容都已被移至该目录。
  • 还要别的吗

    • 您应该收到一条错误消息,并得到令人满意的缓解。

1
是的,使用旧的sh东西,我忘了用它进行调试,但是关于我的原始问题,这意味着问题出在shell上mv吗?真是令人讨厌,它比我最初想象的要简单,但这是一个真正的陷阱。
2014年

5
@ user2485710,关键是在Unix中,shell负责在将命令行参数传递给命令之前扩展通配符。在Windows中,每个命令必须自己扩展通配符。这允许Unix shell提供可与任何命令一起使用的高级通配符功能。
cjm

2
@mikeserv考虑到这些文件不是那么重要,我急于清理并跳到下一步,但是我可以确认它们现在出现在我对第一个帖子/问题的编辑中。
user2485710 2014年

6
@mikeserv tl; dr,*不是一个参数吗?对?:)
Bernhard

1
@Bernhard-实际上,这是我未涉及的一种情况-因为可能是这样。
mikeserv

18

首先,shell扩展./*到当前目录中的所有文件(以点开头的文件除外)。

  • 如果没有文件或只有一个文件:mv失败
  • 如果有两个文件:第一个移到第二个(因此丢失)
  • 如果有两个以上的文件:
    • 如果最后一个是目录:所有文件都移到该目录中
    • 否则mv失败。

1
谢谢。如何分辨哪个子目录是“最后一个”?
蒂姆(Tim)

7
只需致电echo ./*,看看您的外壳使用哪个顺序(通常是字母顺序)。
jofel

如果一个文件失败,为什么不这样呢?
Noumenon

@ Noumenon我不明白你的评论。mv如果仅使用一个参数调用,则返回错误消息。
jofel

你是对的。现在,missing destination file operand after *filename*即使昨天没有,我历史上的命令也一样。
Noumenon

4

当您键入内容时mv ./*,您的外壳程序将./*在执行之前展开mv

注意事项:

  • 如果./*扩展为少于2个参数,mv则在逻辑上将产生错误。
  • ./* 通常会扩展到当前目录中存在的每个文件(包括目录),而不是以点开头。
  • 您可以./*通过阅读shell文档(man 7 glob是该主题的入口点)来控制扩展内容。不同的外壳将具有不同的选择。

1

怎么mv *办?

这是一个简短的答案:

Shell将通配符扩展*到目录内容列表。然后,shell将完整列表传递给命令。该命令永远不会出现*

该命令mv file1 file2 ... filen directory将把file1 ... filen移到目录中。

在这里,我创建一个包含三个文件的测试目录

$ mkdir t
$ cd t
$ echo a>a; echo b>b; echo c>c
$ ls
a  b  c

您不能将多个文件移动到单个文件中

$ mv *
mv: target `c' is not a directory

让我们添加一个子目录

$ mkdir d

可以将多个文件移动到子目录中

$ mv *
$ ls
d
$ ls d
a  b  c

该命令mv file1 file2 ... filen directory几乎没有任何关系*
mikeserv

@迈克:我的回答指出,外壳扩展的最后阶段有效地将外壳转换为前者。不知道这似乎是OP混乱的根源。
RedGrittyBrick 2014年

是的,但是我要说的是,除非遵循以下语言环境,否则shell不会扩展*file dir其中。df
mikeserv

@mikeserv:有这样一个语言环境,我的例子是从Putty剪切和粘贴到CentOS 5.6 GNU / Linux系统的连接。
RedGrittyBrick 2014年

那是哪个地区?你的例子a b c d是不是file ... dir。我只有在所有的评论,因为你没有提到的那种任何地方只说*成为file ... dir这不会发生。
mikeserv
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.