cp 带有一个包含通配符的参数

Tul*_*ova 19 shell cp wildcards arguments

如果我有以下 2 个文件和 1 个文件夹:

someuser@computer:~/Desktop/test$ ls -l
total 340
-rw-r--r-- 1 someuser someuser  45082 ago  5 09:56 file1.pdf
-rw-r--r-- 1 someuser someuser 291836 ago  5 09:56 file2.pdf
drwxrwxr-x 2 someuser someuser   4096 ago  5 09:56 this_is_a_folder.pdf
Run Code Online (Sandbox Code Playgroud)

然后我运行以下命令(注意我省略了目的地):

cp *.pdf
Run Code Online (Sandbox Code Playgroud)

file1.pdf并file2.pdf复制到this_is_a_folder.pdf文件夹中。

someuser@computer00:~/Desktop/test$ ls this_is_a_folder.pdf/
file1.pdf  file2.pdf
Run Code Online (Sandbox Code Playgroud)

显然*.pdf是扩展到匹配项,所以它等价于

cp file1.pdf file2.pdf this_is_a_folder.pdf
Run Code Online (Sandbox Code Playgroud)

...和this_is_a_folder.pdf文件夹一样,然后将两个文件复制到其中。

这是一个错误吗?

这显然是通配符扩展的副作用,这不是我所期望的。

我会预料到一个missing destination file 错误。

Kar*_*tik 54

这不是cp命令中的错误。当您输入时cp *.pdf,cp永远不会看到实际的通配符,因为通配符是由 展开的bash,而不是由展开的cp。如何cp知道您只输入了一个参数?这是 bash 通配符的副作用,不能称为错误。

  • `s/bash/shell/g` (12认同)

ter*_*don 23

你似乎非常了解正在发生的事情。在您的示例中,*pdf确实扩展到file1.pdf file2.pdf this_is_a_folder.pdf. 我不明白你有什么困惑。cp正在做它应该做的事情,你告诉它复制file1.pdf并file2.pdf进入this_is_a_folder.pdf,这正是它正在做的。没有错误,它像宣传的那样工作。

由于您的文件夹的名称以 结尾.pdf,因此它包含在文件夹中,*.pdf并且因为它是一个文件夹,所以最后一个参数(按字母顺序排序)cp将文件复制到其中。要获得您期望的行为,您需要保护通配符免受 shell 的影响,以便在cp看到它之前不会扩展它:

$ cp "*pdf"
cp: missing destination file operand after `*pdf'
Try `cp --help' for more information.
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下,通配符没有扩展,因此cp实际上是在寻找名为*.pdf. 因此,即使您将目录作为最后一个参数 ( cp "*.pdf" foo/)调用它,它也会抱怨cannot stat '*.pdf': No such file or directory. 如果您尝试cp *pdf在仅包含一个以 in 结尾的文件的目录中尝试,您还将看到预期的行为,.pdf因为*.pdf将扩展为仅一个参数:

$ ls -l
total 0
-rw-r--r-- 1 terdon terdon 0 Aug  5 16:56 file1.pdf
$ cp *pdf
cp: missing destination file operand after `file1.pdf'
Try `cp --help' for more information.
Run Code Online (Sandbox Code Playgroud)

也与此比较:

$ ls -l
total 0
drwxr-xr-x 1 terdon terdon 0 Aug  5 16:56 a_folder.pdf
-rw-r--r-- 1 terdon terdon 0 Aug  5 16:56 file1.pdf
-rw-r--r-- 1 terdon terdon 0 Aug  5 16:56 file2.pdf
$ cp *pdf
cp: target `file2.pdf' is not a directory
Run Code Online (Sandbox Code Playgroud)

在这里,由于文件夹的名称以 开头a,*.pdf因此扩展为: a_folder.pdf file1.pdf file2.pdf。因此,cp实际运行的命令是

cp a_folder.pdf  file1.pdf  file2.pdf
Run Code Online (Sandbox Code Playgroud)

由于最后一个参数不是目录,因此返回错误。


Bra*_*iam 9

正如其他答案已经指出的那样,bash 扩展了通配符,然后将它看到的内容传递给cp. 在你的情况下,cp看到file1.pdf file2.pdf this_is_a_folder.pdf. 现在让我们阻止它。

  • 不要使用通配符。
  • 使用-t,--target-directory开关并指定目标。
  • 使用通配符后,始终在最后声明目的地。

    cp *.pdf /I/want/to/copy/files/here
    
    Run Code Online (Sandbox Code Playgroud)


pjc*_*c50 8

这不是错误,而是在 shell 中进行一次通配符扩展而不是在每个程序中实现它的副作用。

现在,您可以通过一些更奇怪的方式来解决这个问题,尤其是通过创建名称以“-”开头的文件。例如(在一个空目录中):

$ touch -- --version
$ ls
--version
$ rm *
rm (coreutils) 5.2.1
Written by Paul Rubin, David MacKenzie, Richard Stallman, and Jim Meyering.

Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ ls
--version
Run Code Online (Sandbox Code Playgroud)

通配符“*”扩展为被解释为开关的文件名。

您还可以通过在文件名中放置空格、制表符和换行符来造成混乱。

  • 这也可以很好地说明为什么应该使用 `ls` 而不是 `ls *`。 (2认同)