cp com um único argumento contendo curingas [duplicados]

11
    

Esta pergunta já tem uma resposta aqui:

    

Se eu tiver os dois arquivos a seguir e uma pasta:

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

E eu corro o seguinte comando (percebo que eu omito o destino):

cp *.pdf

file1.pdf e file2.pdf são copiados na pasta this_is_a_folder.pdf .

someuser@computer00:~/Desktop/test$ ls this_is_a_folder.pdf/
file1.pdf  file2.pdf

Obviamente, *.pdf está expandindo para itens correspondentes, por isso é equivalente a

cp file1.pdf file2.pdf this_is_a_folder.pdf

... e como this_is_a_folder.pdf é uma pasta, os dois arquivos são copiados para ela.

Isso é um bug?

É obviamente um efeito colateral da expansão de curinga e não é o que eu esperaria que acontecesse.

Eu teria esperado um missing destination file erro .

    
por Tulains Córdova 05.08.2013 / 16:44

5 respostas

47

Isso não é um bug no comando cp . Quando você digita cp *.pdf , cp nunca vê os curingas reais porque os curingas são expandidos por bash , não por cp . Como cp saberá que você digitou apenas um argumento? Este é um efeito colateral dos curingas do bash e não pode ser chamado de bug.

    
por 05.08.2013 / 16:52
21

Você parece entender o que está acontecendo perfeitamente bem. No seu exemplo, *pdf de fato se expande para file1.pdf file2.pdf this_is_a_folder.pdf . Eu não vejo o que está te confundindo. cp está fazendo exatamente o que deveria, você está dizendo para copiar file1.pdf e file2.pdf para this_is_a_folder.pdf e é exatamente isso que está fazendo. Não há bug, está funcionando como anunciado.

Como o nome da sua pasta termina em .pdf , ele é incluído em *.pdf e, como é uma pasta e o último argumento (classificado em ordem alfabética), cp copia os arquivos para ele. Para obter o comportamento esperado, é necessário proteger o curinga do shell para que ele não seja expandido antes que cp o veja:

$ cp "*pdf"
cp: missing destination file operand after '*pdf'
Try 'cp --help' for more information.

Observe que, nesse caso, o curinga não é expandido, portanto cp está procurando um arquivo chamado *.pdf . Então, mesmo se você fosse chamá-lo com um diretório como o último argumento ( cp "*.pdf" foo/ ), ele reclamaria sobre cannot stat '*.pdf': No such file or directory . Você também verá seu comportamento esperado se tentar cp *pdf em um diretório que contenha apenas um arquivo que termine em .pdf porque *.pdf será expandido para apenas um argumento:

$ 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.

Compare também com isso:

$ 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

Aqui, como o nome da pasta começa com a , *.pdf é expandido para: %código%. Portanto, o comando a_folder.pdf file1.pdf file2.pdf que está sendo executado é

cp a_folder.pdf  file1.pdf  file2.pdf

O que retorna um erro porque o último argumento não é um diretório.

    
por 05.08.2013 / 16:53
8

Não é um bug, é um efeito colateral de fazer expansão de curingas uma vez no shell, em vez de implementá-lo em cada programa.

Agora, existem algumas maneiras muito estranhas para você se enganar com isso, especialmente criando arquivos cujos nomes começam com "-". Por exemplo (em um diretório vazio):

$ 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

O curinga '*' se expande para o nome do arquivo, que é interpretado como um switch.

Você também pode causar o caos colocando espaços, guias e novas linhas em nomes de arquivos.

    
por 05.08.2013 / 17:48
8

Como as outras respostas já apontaram, o bash expande o curinga e passa o que vê para cp . No seu caso, cpfile1.pdf file2.pdf this_is_a_folder.pdf . Agora vamos evitar isso.

  • Não use curingas.
  • Use a opção -t , --target-directory e especifique o destino.
  • Sempre declare no final um destino depois de usar um curinga.

    cp *.pdf /I/want/to/copy/files/here
    
por 05.08.2013 / 17:24
4

Se o último parâmetro da parte for um diretório, cp copiará os arquivos especificados para ele. Não importa se você nomeou seu diretório foo.pdf (por que um nome assim ?!). A expansão de curingas é baseada no nome do arquivo (ou nome do diretório), não no tipo de arquivo.

Com dois argumentos, o destino pode ser um arquivo ou diretório. No caso de um arquivo, o arquivo de destino é removido e substituído por uma cópia do arquivo de origem. Se o destino for um diretório, uma cópia do arquivo de origem será colocada nesse diretório. Observe uma das sinopse:

cp [OPTION]... [-T] SOURCE DEST

Com três ou mais argumentos, o destino é tratado como um diretório:

cp [OPTION]... SOURCE... DIRECTORY
    
por 05.08.2013 / 16:48