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

48
  • ao especificar ls --directory a*, deve listar apenas diretórios começando coma*
  • MAS lista arquivos E diretórios começando com a

Perguntas :

  • onde posso encontrar alguma documentação sobre isso, além de mane infoonde acho que olhei minuciosamente?
  • isso funciona apenas no BASH?
erch
fonte
1
Veja também esta outra pergunta muito semelhante .
Stéphane Chazelas
5
echo a*também listará os arquivos que começam com a(se houver). Apenas para deixar mais claro que não está lsfazendo isso, mas sim o bash.
ash108

Respostas:

89

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

Quando você digita

ls a*

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

Para fins de expansão de curinga, "arquivos" refere-se a todas as entidades no diretório atual. Por exemplo, a1pode ser um arquivo normal, a2um diretório e a3um link simbólico. Todos eles têm entradas de diretório e a expansão de 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 encontrará (bash, sh, ksh, zsh, csh, tcsh, ...) implementam curingas. Os detalhes podem variar, mas a sintaxe básica de *corresponder zero ou mais caracteres e ?qualquer caractere único é 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 bashe procure por "expansão de nome de arquivo" ou veja aqui .

O fato de isso ser 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 curinga é consistente para (quase) todos os comandos; se o shell não fizesse isso, inevitavelmente alguns comandos não se incomodariam e outros o fariam de maneiras sutilmente diferentes que o autor pensava serem "melhores". (Acho que o shell de comando do Windows tem esse problema, mas 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

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 serão renomeados. Alguns comandos (como find) podem fazer sua própria expansão de curinga; você precisa citar os argumentos para suprimir a expansão do shell:

find . -name '*.txt' -print

A expansão do curinga do shell se baseia 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ê deseja mover todos os .logarquivos para o diretório pai, pode digitar:

mv *.log ..

Se você esquecer o ..:

mv *.log

e houver exatamente dois .logarquivos no diretório atual, ele será expandido para:

mv one.log two.log

que irá renomear one.loge derrotar two.log.

EDIT : E depois de 52 votos positivos, um aceito e um distintivo de Guru, talvez eu deva realmente responder à pergunta no título.

A opção -dou não indica para listar apenas diretórios. Ele diz para listar diretórios da mesma forma que eles, não seu conteúdo. Se você fornecer um nome de diretório como argumento , por padrão, ele listará o conteúdo do diretório, já que geralmente é disso que você está interessado. A opção diz para ele listar apenas o próprio diretório. Isso pode ser particularmente útil quando combinado com caracteres curinga. Se você digitar:--directorylsls-d

ls -l a*

lsfornecerá uma lista longa de cada arquivo cujo nome começa com ae do conteúdo de cada diretório cujo nome começa com a. Se você deseja 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 que o lscomando nunca vê o *personagem.

Quanto a onde isso está documentado, man lsmostrará a documentação para o lscomando em praticamente qualquer sistema semelhante ao Unix. Na maioria dos sistemas baseados em Linux, o lscomando faz parte do pacote GNU coreutils; se você possui o infocomando, info lsou info coreutils lsdeve fornecer uma documentação mais definitiva e abrangente. Outros sistemas, como o MacOS, podem usar versões diferentes do lscomando e podem não ter o infocomando; para esses sistemas, use man ls. E ls --helpmostrará uma mensagem de uso relativamente curta (117 linhas no meu sistema) se você estiver usando a implementação do coreUtil GNU.

E sim, mesmo os especialistas precisam consultar a documentação de vez em quando. Veja também esta piada clássica .

Keith Thompson
fonte
8
@ Thomas: a*expande para uma lista de todos os arquivos no diretório atual cujos nomes começam com a.
Keith Thompson
2
@Thomas: Ou em qualquer diretório que você especificar:ls subdir/a*
Keith Thompson
1
Para realmente ver o comando executado após a expansão do shell, echoele. Então, se você quer saber o que está acontecendo quando você faz ls a*, primeiro executarecho ls a*
Carlos Campderrós
1
ou apenas echo a*... o shell faz expansão glob de qualquer maneira
Useless
2
@ sendmoreinfo: Isso depende do shell e das configurações. No csh e no tcsh, uma expansão glob com falha é um erro. Em festa, shopt -s failglobfaz com que o mesmo comportamento. Definir, nullglobmas não failglobfaz, por exemplo, *nosuchfile*expandir para uma sequência vazia.
Keith Thompson
27

Veja a resposta de Keith Thompson; mas para explicar por que ls --directory a*arquivos espectáculos e diretórios: A --directoryopção não faz arquivos não-diretório reprimir. Em vez disso, lista os diretórios como tal, enquanto listaria seu conteúdo. Exemplo:

$ mkdir foo
$ touch foo/bar
$ ls foo
bar
$ ls --directory foo
foo
chirlu
fonte
3
que exemplo é mais atraente com a -Fopção
glenn jackman
6

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

-d, --directory lista entradas de diretório em vez de conteúdo e não remove a referência de links simbólicos

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

Se FILE for um diretório, mostre a própria entrada do diretório em vez de listar o conteúdo desse diretório. Se FILE for um link simbólico, mostre a própria entrada do link em vez do arquivo apontado pelo link.

msw
fonte
Para ser pedante, enquanto a opção -d pode ser explicada (se houver) na página do manual, a expansão do argumento e o curinga não são documentados na página do manual ls, pois ela é feita pelo shell. Se você desativou a expansão do nome do arquivo em seu shell, "ls a *" mostraria apenas um arquivo literalmente chamado de 'a *'.
Johnny
Para ser pedante, enquanto a expansão do shell foi respondida por outros entrevistados, nenhum deles aborda a explicação escassa e como ela pode ser mal interpretada. Se você gostaria que eu repetisse o que já foi bem dito, seja mais direto.
quer
4

Globbing

Como foi explicado, a expansão de *(e expansões similares) é chamada de globbing no jargão do Unix e geralmente é um recurso do processador de comandos (conhecido como "shell" na linguagem do Unix). Portanto, o globbing também pode ser usado em muitos outros lugares; digite man 7 globno shell de uma distribuição clássica do Linux (ou veja isso ) para obter mais informações sobre o globbing.

No início do Unix, globna verdade , era implementado por um programa separado chamado /etc/glob(consulte a página 10 deste antigo manual do UNIX para obter a documentação). Atualmente, é uma rotina de código fornecida por bibliotecas de código e é comumente usada por shells. Fonte : Wikipedia .

Diretórios

Por que ls -dlista arquivos e diretórios ...

A lspágina de manual explica por que isso acontece, mas com uma explicação muito concisa. Então, aqui está uma tentativa de uma explicação expandida:

Por padrão, lslista o conteúdo dos diretórios quando recebem seus nomes e fará o mesmo com links simbólicos para diretórios. A -dopção significa "quando houver nomes de diretório (s)" (que também podem ser atribuídos implicitamente por globbing) , apenas mostre o _name_s do diretório (s), mas não seu conteúdo. Da mesma forma, quando fornecido com nomes explícitos ou implícitos de links simbólicos para diretórios , mostre o nome do arquivo do link simbólico, não o conteúdo do diretório ao qual ele faz referência.

A -dopção não tem nada a ver, até onde 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 existe uma boa maneira de fazer isso apenas com o GNU ls. Aqui estão alguns exemplos de como usar o findcomando

Para resumir: Por padrão, lsmostra o conteúdo dos diretórios quando recebe o nome do caminho. -daltera esse comportamento, mostrando apenas o próprio nome do diretório, como seria feito para um arquivo padrão.

Abbafei
fonte
3

A documentação não diz que lista apenas as entradas de diretório, mas, quando lsrecebe o nome do diretório, lista a entrada de diretório em vez de seu conteúdo. A melhor maneira de entender é por 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 /
defhlt
fonte
2

A documentação faz 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 Bourne é

  1. Expansão Tilde
  2. Expansão de parâmetros
  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 cotação

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

Jens
fonte
1

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

Hauke ​​Laging
fonte
3
mais como "Expansão do nome do caminho" ou "Geração do nome do arquivo". Relacionado a "correspondência de padrão", mas não é o mesmo.
Stéphane Chazelas
@StephaneChazelas De fato, mas "correspondência de padrão" é uma subseção de "expansão de nome de caminho" na página de manual, enquanto "Geração de nome de arquivo" não ocorre lá (apenas no documento informativo).
Hauke ​​Laging