por que o ls -d também lista arquivos e onde está documentado?

47
  • ao especificar ls --directory a* , deve listar apenas os diretórios que começam com a*
  • MAS lista arquivos e diretórios que começam com a

Perguntas :

  • onde eu posso encontrar alguma documentação sobre isso, além de man e info , onde eu acho que eu olhei completamente?
  • isso funciona apenas no BASH?
por erch 08.05.2013 / 00:19

7 respostas

87

A sintaxe a* e *a* é implementada pelo shell, não pelo comando ls .

Quando você digita

ls a*

em seu prompt de shell, o shell expande a* para uma lista de todos os arquivos existentes no diretório atual cujos nomes começam com a . Por exemplo, pode expandir a* para a sequência a1 a2 a3 e passar esses como argumentos para ls . O comando ls nunca vê o caractere * ; ele só vê os três argumentos a1 , a2 e a3 .

Para fins de expansão de caractere curinga, "arquivos" refere-se a todas as entidades no diretório atual. Por exemplo, a1 pode ser um arquivo normal, a2 pode ser um diretório e a3 pode ser um symlink. Todos eles têm entradas de diretório, e a expansão de caractere curinga do shell não se importa com o tipo de entidade a que essas entradas se referem.

Praticamente todos os shells com os quais você provavelmente executará (bash, sh, ksh, zsh, csh, tcsh, ...) implementam curingas. Os detalhes podem variar, mas a sintaxe básica de * que corresponde a zero ou mais caracteres e ? correspondente a qualquer caractere é razoavelmente consistente.

Para o bash em particular, isso está documentado na seção "Expansão do nome do arquivo" do manual do bash; execute info bash e pesquise "Expansão de nome de arquivo" ou consulte aqui .

O fato de que isso é feito pelo shell, e não por comandos individuais, tem algumas conseqüências interessantes (e às vezes surpreendentes). A melhor coisa é que o manuseio de curingas é consistente para (quase) todos os comandos all ; se a concha não fizesse isso, inevitavelmente alguns comandos não se incomodariam, e outros o fariam de maneiras sutilmente diferentes, que o autor achava "melhor". (Eu acho que o shell de comando do Windows tem esse problema, mas eu não estou familiarizado o suficiente para comentar mais.)

Por outro lado, é difícil escrever um comando para renomear vários arquivos. Se você escrever:

mv *.log *.log.bak

ele provavelmente falhará, pois *.log.bak é expandido com base nos arquivos que já existem no diretório atual. Existem comandos que fazem esse tipo de coisa, mas eles precisam usar sua própria sintaxe para especificar como os arquivos devem ser renomeados. Alguns comandos (como find ) podem fazer sua própria expansão de curingas; você tem que citar os argumentos para suprimir a expansão do shell:

find . -name '*.txt' -print

A expansão de curinga do shell é baseada inteiramente na sintaxe do argumento da linha de comando e no conjunto de arquivos existentes. não pode ser afetado pelo significado do comando. Por exemplo, se você quiser mover todos os arquivos .log para o diretório pai, digite:

mv *.log ..

Se você esquecer o .. :

mv *.log

e existem exatamente dois arquivos .log no diretório atual, ele será expandido para:

mv one.log two.log

que renomeará one.log e clobber two.log .

EDITAR : E depois de 52 votos positivos, um selo de aceitação e um Guru, talvez eu deva responder a pergunta no título.

A opção -d ou --directory para ls não diz para listar apenas diretórios. Diz-lhe para listar os diretórios como eles mesmos, não o seu conteúdo. Se você der um nome de diretório como um argumento para ls , por padrão ele irá listar o conteúdo do diretório, já que normalmente é o que você está interessado. A opção -d diz para lista apenas o diretório em si. Isso pode ser particularmente útil quando combinado com curingas. Se você digitar:

ls -l a*

ls fornecerá uma lista longa de cada arquivo cujo nome começa com a e do conteúdo de cada diretório cujo nome começa com a . Se você quer apenas uma lista dos arquivos e diretórios, uma linha para cada, você pode usar:

ls -ld a*

que é equivalente a:

ls -l -d a*

Lembre-se novamente de que o comando ls nunca vê o caractere * .

Quanto a onde isso é documentado, man ls mostrará a documentação do comando ls em praticamente qualquer sistema semelhante ao Unix. Na maioria dos sistemas baseados em Linux, o comando ls faz parte do pacote GNU coreutils; Se você tiver o comando info , info ls ou info coreutils ls deverá fornecer uma documentação mais definitiva e abrangente. Outros sistemas, como o MacOS, podem usar versões diferentes do comando ls e podem não ter o comando info ; para esses sistemas, use man ls . E ls --help mostrará uma mensagem de uso curto relativamente (117 linhas no meu sistema) se você estiver usando a implementação GNU coreutils.

E sim, até os especialistas precisam consultar a documentação agora e depois. Veja também esta piada clássica .

    
por 08.05.2013 / 00:25
27

Veja a resposta de Keith Thompson; mas para explicar porque ls --directory a* mostra arquivos e diretórios: A opção --directory não suprime arquivos não-diretório. Em vez disso, ele lista os diretórios como tal, enquanto, de outra forma, listaria seu conteúdo. Exemplo:

$ mkdir foo
$ touch foo/bar
$ ls foo
bar
$ ls --directory foo
foo
    
por 08.05.2013 / 00:31
6

Para ser muito explícito, está documentado na página de manual do ls (1) :

-d, --diretório lista as entradas do diretório em vez do conteúdo e não desrefere os links simbólicos

para ser justo, "entradas em vez de conteúdo" provavelmente seriam mais explicativas:

If FILE is a directory, show the directory entry itself instead of listing the contents of that directory. If FILE is a symbolic link, show the link entry itself instead of the file pointed to by the link.

    
por 08.05.2013 / 02:54
4

Globbing

Como foi explicado, a expansão de * (e expansões similares) é chamada glob bing no jargão do Unix, e normalmente é um recurso do processador de comandos (conhecido como "shell" no jargão do Unix). Então globbing pode ser usado em muitos outros lugares também; digite man 7 glob no shell de uma distribuição clássica do Linux (ou consulte this ) para mais sobre glob bing.

No início do Unix, glob foi realmente implementado por um programa separado chamado /etc/glob (veja na página 10 do este antigo manual do UNIX para documentação ). Hoje em dia, é uma rotina de código fornecida por bibliotecas de código e é comumente usada por shells. Fonte : Wikipedia .

Diretórios

Por que ls -d lista arquivos assim como diretórios ...

A ls man page explica por que isso acontece, mas com uma explicação concisa. Então, aqui está uma tentativa de uma explicação expandida:

Por padrão, ls lista os conteúdos dos diretórios quando recebe seus nomes, e fará o mesmo com symlinks nos diretórios. A opção -d significa, "quando dado nome (s) de diretório (s)" (que também pode ser dado implicitamente por glob bing) , apenas mostrar o _name_s do (s) diretório (s), mas não seu conteúdo. Da mesma forma, quando fornecido com (explicitamente ou implicitamente ) nome (s) de links simbólicos para diretórios , mostre o nome do arquivo do link simbólico, não o conteúdo do diretório que ele referencia .

A opção -d não tem nada a ver, até onde eu sei, com quais itens estão listados; isso pode ser feito (fonte: aqui ) com find , assim: find . -maxdepth 1 -type d . Não tenho certeza se há uma boa maneira de fazer isso apenas com o GNU ls . Aqui estão alguns exemplos de como usar o comando find .

Então, para resumir: Por padrão, ls mostra o conteúdo dos diretórios quando recebe seu nome de caminho. -d altera esse comportamento, mostrando apenas o próprio nome do diretório, como seria feito para um arquivo padrão.

    
por 09.05.2013 / 06:10
3

A documentação não diz que lista as entradas do diretório somente , mas quando ls recebe o nome do diretório, ele lista a entrada do dir ao invés de seu conteúdo. A melhor maneira de entender é pelo exemplo:

> {ice} ~ :10:47 % ls -l / 
total 97
drwxr-xr-x   2 root root  4096 May  3 00:27 bin
drwxr-xr-x   4 root root  1024 May  3 14:17 boot
drwxr-xr-x   2 root root  4096 Apr 29 13:44 cdrom
drwxr-xr-x  18 root root  4420 May  9 09:58 dev
...
lrwxrwxrwx   1 root root    33 May  3 14:16 vmlinuz -> boot/vmlinuz-3.9.0-030900-generic
lrwxrwxrwx   1 root root    29 May  3 11:07 vmlinuz.old -> boot/vmlinuz-3.8.0-19-generic
> {ice} ~ :10:47 % ls -ld /
drwxr-xr-x 25 root root 4096 May  3 14:16 /
    
por 09.05.2013 / 09:48
2

A documentação é parte do shell . Em particular, o shell executa várias expansões e substituições em uma ordem específica antes de executar um comando.

A sequência de expansões de palavras para um shell compatível com o Bourne é

  1. Expansão de til
  2. Expansão do parâmetro
  3. Substituição de comando
  4. Expansão aritmética
  5. Divisão de campo
  6. Expansão do nome do caminho
  7. Remoção de citações

Portanto, o comando ls nem mesmo vê os caracteres * , os argumentos já estão expandidos com todos os arquivos correspondentes ao padrão a* glob. Isso é diferente do Windows, onde cada comando que precisa de globbing de nome de arquivo precisa implementar esse recurso em si.

    
por 08.05.2013 / 09:20
1

A palavra chave que você precisa ( man bash ) é "Expansão do nome do caminho".

    
por 08.05.2013 / 00:29