Saída diferente dos comandos “ls. *” e “ls *.”

2

O comando

    ls .*

quando run dá como resultado o seguinte:

  • Todos os arquivos no diretório atual, começando com a. (arquivos ocultos)
  • Todos os arquivos nos diretórios ocultos presentes no diretório atual
  • Todos os arquivos no diretório atual
  • Todos os arquivos no diretório pai

Por que o comando

    ls *.

não exibir:

  • Todos os arquivos no diretório atual
  • Todos os arquivos no diretório pai

O motivo pelo qual estou pensando é: a expressão regular *. deve corresponder a ambos. e .. Então ls deve ser executado em ambos e, portanto, a saída que estou esperando deve ser exibida

    
por crisron 31.12.2013 / 11:55

2 respostas

6

É porque * não corresponde aos arquivos que começam com . por padrão. Considere o seguinte diretório:

$ ls -la 
total 8404
drwxrwxrwx   2 terdon terdon 8105984 Dec 31 13:14 .
drwxr-xr-x 153 terdon terdon  491520 Dec 30 22:32 ..
-rw-r--r--   1 terdon terdon       0 Dec 31 13:14 .dotfile
-rw-r--r--   1 terdon terdon       0 Dec 31 13:14 file1
-rw-r--r--   1 terdon terdon       0 Dec 31 13:14 file2
-rw-r--r--   1 terdon terdon       0 Dec 31 13:14 file3.

Vamos ver o que cada um dos globs que você usou se expande para:

$ echo .*
. .. .dotfile

$ echo *.
file3.

$ echo *
file1 file2 file3.

Como você pode ver, o * não inclui arquivos ou diretórios que começam com . , portanto, ./ e ../ são ignorados. A mesma coisa acontece com o seu ls exemplo. Em bash , você pode alterar isso com o parâmetro dotglob :

$ shopt -s dotglob
$ echo .*
. .. .dotfile

Outras camadas se comportam de maneira diferente, por exemplo csh :

% echo .*
. .. .dotfile
    
por 31.12.2013 / 12:19
3

A regra para expansão de nome de arquivo tem um caso especial para . como o primeiro caractere em um nome de arquivo: deve ser explicitamente correspondido (ou seja, o padrão deve conter um . inicial ou . após / ). Caso contrário, esses arquivos não são candidatos.

É por isso que sua primeira versão seleciona nomes de arquivos que começam com . , mas o segundo não. * não corresponde a . como o primeiro caractere de um nome de arquivo.

Idioma de Comando do POSIX Shell descreve-o como:

If a filename begins with a period ( '.' ), the period shall be explicitly matched by using a period as the first character of the pattern or immediately following a slash character. The leading period shall not be matched by:

  • The asterisk or question-mark special characters
  • A bracket expression containing a non-matching list, such as "[!a]", a range expression, such as "[%-0]", or a character class expression, such as "[[:punct:]]"

It is unspecified whether an explicit period in a bracket expression matching list, such as "[.abc]", can match a leading period in a filename.

Seu shell pode ter opções para alterar esse comportamento. O Bash tem isso, por exemplo ( expansão do nome do arquivo ):

When a pattern is used for filename expansion, the character ‘.’ at the start of a filename or immediately following a slash must be matched explicitly, unless the shell option dotglob is set. When matching a file name, the slash character must always be matched explicitly. In other cases, the ‘.’ character is not treated specially.

Note que estas são não expressões regulares. .* como um regex corresponderia a qualquer coisa (incluindo nada). *. seria mal formado.

    
por 31.12.2013 / 12:17