Como posso fazer com que "ls" mostre arquivos de ponto primeiro sem fazer distinção entre maiúsculas e minúsculas?

21

Crie os seguintes arquivos em um diretório

$ touch .a .b a b A B 你好嗎

Meu lspedido padrão ignora a presença de pontos iniciais, misturando-os com os outros arquivos.

$ ls -Al
total 0
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 a
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 .a
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 A
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 b
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 .b
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 B
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:06 你好嗎

Eu posso mudar LC_COLLATE para colocar os arquivos de ponto em primeiro lugar.

$ LC_COLLATE=C ls -Al
total 0
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 .a
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 .b
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 A
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 B
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 a
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 b
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:06 你好嗎

Infelizmente isso faz com que a ordem de classificação entre maiúsculas e minúsculas, ou seja, Ae Bprecedem ae b. Existe uma maneira de imprimir arquivos de ponto primeiro, mantendo a distinção entre maiúsculas Ae minúsculas ( e aprecedendo Be b)?

Editar: tentando modificar LC_COLLATE

Até agora, nenhuma das respostas replica totalmente a funcionalidade lsfacilmente. É concebível que eu poderia agrupar alguns deles em uma função, mas isso teria que incluir algum código detalhado sobre (por exemplo) como trabalhar sem argumento versus fornecer um diretório como argumento. Ou como lidar com uma -dbandeira explícita .

Como alternativa, pensei que talvez pudesse ser melhor LC_COLLATEusar. No entanto, não consigo fazer isso funcionar. Atualmente estou usando LC_COLLATE="en_AU.UTF-8". Eu verifiquei /usr/share/i18n/locales/en_AU(embora não tenha certeza se esse é o arquivo certo, pois não consigo ver nenhuma referência UTF-8); Encontrei o seguinte.

LC_COLLATE
copy "iso14651_t1"
END LC_COLLATE

/usr/share/i18n/locales/iso14651_t1contém copy "iso14651_t1_common". Finalmente, /usr/share/i18n/locales/iso14651_t1_commoncontém

 <U002E> IGNORE;IGNORE;IGNORE;<U002E> # 47 .

Excluí esta linha, executei sudo locale-gene reiniciei o meu computador. Infelizmente, isso não mudou nada.

Sparhawk
fonte

Respostas:

11

O OP estava muito próximo da edição /usr/share/i18n/locales/iso14651_t1_common, mas o truque é não excluir a linha

<U002E> IGNORE;IGNORE;IGNORE;<U002E> # 47 .

mas sim modificá-lo para

<U002E> <RES-1>;IGNORE;IGNORE;<U002E> # 47 .

Por que isso funciona

As IGNOREinstruções especificam que o ponto final (também conhecido como ponto ou caractere <U002E>) será ignorado ao ordenar palavras em ordem alfabética. Para fazer com que seus arquivos de ponto cheguem primeiro, mude IGNOREpara um símbolo de intercalação que vem antes de todos os outros caracteres. Os símbolos de intercalação são definidos por linhas como

collating-symbol <something-inside-angle-brackets>

e eles são ordenados pela aparência da linha

<something-inside-angle-brackets>

Na minha cópia de iso14651_t1_common, o símbolo de intercalação em primeiro lugar é <RES-1>, que aparece na linha 3458. Se você apresentar um arquivo diferente, use o símbolo de intercalação que for solicitado primeiro.

Detalhes sobre a ordenação de caracteres com LC_COLLATE

<U002E>possui três IGNOREdeclarações porque as cartas podem ser comparadas várias vezes em caso de empate. Para entender isso, considere letras minúsculas ae maiúsculas A(que fazem parte de um grupo de caracteres que na verdade são comparados quatro vezes):

<U0061> <a>;<BAS>;<MIN>;IGNORE # 198 a
<U0041> <a>;<BAS>;<CAP>;IGNORE # 517 A

Ter várias rodadas de comparação permite que os arquivos que começam com "a" e "A" sejam agrupados porque ambos são comparados como <a>na primeira passagem, com a próxima letra determinando a ordem. Se todas as letras a seguir forem iguais (por exemplo, a.txte A.txt), a terceira passagem será inserida a.txtprimeiro porque o símbolo de intercalação para letras minúsculas <MIN>aparece na linha 3467, antes do símbolo de intercalação para letras maiúsculas <CAP>(linha 3488).

Implementando essa mudança

Se você deseja que o período chegue primeiro sempre que um programa solicita letras LC_COLLATE, é possível modificar iso14651_t1_commonconforme descrito acima e reconstruir o arquivo de locais. Mas se você quiser fazer essa alteração apenas para lse sem acesso root, poderá copiar os arquivos de localidade originais para outro diretório antes de modificá-los.

O que eu fiz

Meu localidade padrão é en_US, então eu copiei en_US, iso14651_t1e iso14651_t1_commonpara $HOME/path/to/new/locales. Lá eu fiz a alteração acima iso14651_t1_commone renomei en_USpara en_DOTFILE. Em seguida, compilei o código do idioma en_DOTFILE com

localedef -i en_DOTFILE -f UTF-8 -vc $HOME/path/to/new/locales/en_DOTFILE.UTF-8

Para substituir a lsordem padrão , crie um script BASH chamado ls:

#!/bin/bash
LOCPATH=$HOME/path/to/new/locales LANG=en_DOTFILE.UTF-8 ls "$@"

salve-o em algum lugar que apareça antes /usr/binno seu caminho e torne-o executável com chmod +x ls.

Molho de feijão
fonte
é claro, você terá que adicionar -a ou -A para ver seus arquivos de ponto, mas, a menos que você sempre queira vê-los, faz sentido fazer isso na linha de comando, não no script BASH
beandip
Brilhante! Obrigado, isso é perfeito! Acabei de modificar o arquivo de propriedade da raiz e não testei seu script. No entanto, acho que você precisa colocar aspas duplas em torno do seu $@.
Sparhawk
boa chamada - aspas duplas adicionadas
beandip
11

Você pode usar ordem de classificação do shell em vez (que pode não envolver a ordem de intercalação do local; bash, AT & T ksh, yash, tcshe zshdar os resultados esperados, mkshe dash. Não fishparece dar uma ordem insensível caso, mas dá resultados diferentes quando há não-ASCII personagens):

ls -dUl -- .* *

Isso fornece lsuma lista explícita de arquivos (e diretórios) a serem listados e desativa lsa classificação ( -Uque é uma extensão GNU).

Existem algumas ressalvas, dependendo do shell que você está usando.

  • Com zsh, a nomatchopção padrão fará com que o comando falhe se o diretório não contiver arquivos ocultos e não ocultos; você pode desativar nomatchpara evitar isso, mas o melhor seria fazer isso set -o cshnullglob(e o comando falhará apenas se nenhum dos globs corresponder como nos (t)cshshells do Unix anteriores).
  • Com zsh, pdkshe sua expansão derivada e fish, .*não inclui .e .., portanto, isso corresponde ls -Al. Com outras conchas .e ..estão incluídos para combinar ls -al. No último caso, você precisará alterar os padrões de globbing para excluir .e ..( ls -dUl -- ..?* .[!.]* *).
  • Exceto em fish, (t)cshou zsh, se algum dos padrões de globbing não corresponder a nada, lsproduzirá uma mensagem de erro; você pode evitar isso, quer definindo a nullglobopção (em bashou zshpelo menos), ou através do redirecionamento stderrpara /dev/null( ls -dUl -- ..?* .[!.]* * 2>/dev/null). Se você usar nullglob, cuidado com o comportamento potencialmente surpreendente que causa (consulte Shell comendo caracteres `?` ). fishse comporta como bashcom nomatchexceção de que, quando interativo, uma mensagem de aviso será emitida para cada glob que não corresponder.

(Com agradecimentos a Stéphane Chazelas por todo o feedback!)

Stephen Kitt
fonte
Observe que nem todas as conchas classificarão a lista usando a ordem de intercalação da localidade. mkshe, dashpor exemplo, não classificará maiúsculas de minúsculas.
Stéphane Chazelas
1
Observe que -U(para significar não classificado) é uma extensão GNU. Algumas outras lsimplementações, como o FreeBSD, têm uma lista, -Umas não para uma lista não classificada.
Stéphane Chazelas
Com GNU ls, você precisa --antes .*de que a implementação aceita opções depois de argumentos (a menos que POSIXLY_CORRECT está no ambiente)
Stéphane Chazelas
Sneaky (+1)! No entanto, não tenho certeza de como eu usaria isso facilmente em todos os casos, ou seja, em um alias ou função. Por exemplo, teria que mudar se eu quiser especificar um diretório específico lscomo argumento.
Sparhawk
1
@PeterCordes [!.]está correto. Veja pubs.opengroup.org/onlinepubs/9699919799/utilities/… . Alguns shells (a maioria?) Permitem ^como sinônimo de !globs de classe de caracteres negados. Em qualquer caso, eu prefiro .[!.] .??* *como sendo um pouco mais compreensível do que.[!.]* ..?* *
jrw32982 suporta Monica
4

Você pode simplesmente usar dois lscomandos separados :

$ ls -dl ..?* .[^.]* 2>/dev/null ; ls -dl *
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 .a
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 .b
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 a
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 A
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 b
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 B
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 你好嗎

Diferentemente das outras respostas até agora, essa abordagem exibe os arquivos de pontos primeiro evitando as entradas .e .., depois as demais entradas em ls ordem alfabética.

As respostas do @StephenKitt podem ser melhoradas para alcançar o mesmo resultado:

$ ls -dUl ..?* .[^.]* * 2>/dev/null
jlliagre
fonte
+1 também, mas, de acordo com a resposta de StephenKitt, não tenho certeza de como usaria isso facilmente em todos os casos, ou seja, em um apelido ou função. Por exemplo, teria que mudar se eu quiser especificar um diretório específico lscomo argumento. (FWIW Eu estou usando zsh, mas isso é útil para bash-pessoas, eu acho.)
Sparhawk
-2

Você pode jogar com as opções de comando ls . Tente o seguinte:

# ls -laXr

Onde:

-l     use a long listing format
-a, --all
              do not ignore entries starting with .
-X     sort alphabetically by entry extension
-r, --reverse
              reverse order while sorting
Rodrigo Calvo
fonte
Desculpe, isso não parece fazer o que eu quero. A -Xbandeira é classificada pela extensão após a ., que é totalmente diferente. Além disso, os arquivos estão em ordem alfabética inversa. Além disso, embora os arquivos de ponto sejam os primeiros no meu exemplo, ele não funcionará em todos os casos (por exemplo a.b c.d .a .c). Além disso, você usou em -avez de -A.
Sparhawk