Como faço para classificar ls caracteres sublinhados primeiro?

20

Eu gosto de poder nomear arquivos e diretórios com um prefixo de sublinhado, se for algo que eu quero manter separado de outros arquivos e diretórios no mesmo nível. No Windows e Mac, por exemplo, o prefixo de um arquivo com um sublinhado o classifica para o topo, na frente de arquivos que começam com um caractere alfanumérico.

Meu google descobriu que tem a ver com LC_COLLATE e meu local atual (en_US). Tudo bem, embora eu realmente não entenda por que o en_US não é o esperado.

Com base na configuração do site de demonstração ICU Collate , o locale para en_US_POSIX certamente parece ter a ordem de classificação que estou procurando (você deve editar os dados da amostra e adicionar alguns sublinhados para testá-los). Mas eu realmente não vejo como aplicar isso no meu shell Linux.

Idealmente, eu gostaria de poder configurar algo na minha configuração do bash para que ele sempre classifique os sublinhados primeiro. Como eu faria isso?

Tom Auger
fonte
Não consigo reproduzir usando ICU Collate com padrões ou com en_US_POSIX.txt através de "Buscar regras para localidade". Você pode explicar as configurações que você usou?
Mikel
Pergunta semelhante askubuntu.com/questions/47702/…
Mikel
@ Mikel usando o link fornecido acima, adicione alguns sublinhados aos dados de teste e envie para ver os resultados da classificação.
Tom Auger
Foi exatamente isso que fiz, e as sequências começando com sublinhados são classificadas no meio, e não no começo, como se os sublinhados não estivessem lá.
Mikel
11
Uma pergunta relacionada, que trata de realmente alterar a definição da ordem de intercalação, é unix.stackexchange.com/questions/421908 .
JdeBP 26/09

Respostas:

5

Se você não conseguir lsclassificar da maneira que quiser, tente a expansão do shell.

Você pode usar padrões de nome de arquivo para executar lscom uma lista de arquivos que o shell já classificou, ignorando o método lsusado.

ls -lf _* [!_]*

Supondo que você tenha os arquivos

_a a _b b _c c

isso é como correr

ls -lf _a _b _c a b c

Explicação:

_* é um padrão de shell que corresponde a qualquer nome de arquivo que comece com um sublinhado, expandido em ordem alfabética.

[!_]*corresponde a qualquer nome de arquivo que não comece com um sublinhado, expandido em ordem alfabética.

-fdiz lspara não classificar, porque o shell já fez.

Mais informações: expansão do nome do arquivo bash

Se houver diretórios no diretório atual, você desejará executar o comando como este para evitar ls listando arquivos nos diretórios:

ls -lfd _* [!_]*
Mikel
fonte
7
A propósito, o DOS / Windows / OSX realmente não coloca sublinhados antes de qualquer outra coisa: eles diferenciam maiúsculas de minúsculas com o sublinhado colocado antes das letras, mas alguns outros caracteres de pontuação vão antes ou depois do sublinhado. Usar _para fazer com que os arquivos apareçam primeiro é uma invasão específica do sistema operacional; e a versão unix desse hack é iniciar o nome do arquivo com uma letra maiúscula: a convenção unix padrão é usar apenas letras minúsculas nos nomes dos arquivos.
Gilles 'SO- stop be evil'
4
Ou zeros; por exemplo 00README.
mattdm
11
@Gilles +1 para a prática recomendada do unix de usar caps em arquivos importantes para torná-los os primeiros. No final das contas, se essa é a convenção, provavelmente é melhor que eu simplesmente a adote, em vez de tentar forçar o unix a se comportar da maneira que outros sistemas operacionais fazem para que eu possa usar as convenções que foram desenvolvidas para Mac ou Windows. Obrigado pela ótima dica.
Tom Auger
11
O @TomAuger -fdiz lspara não fazer sua própria classificação; portanto, ele exibe seus argumentos na ordem em que são passados. O resultado de cada expansão do curinga do shell _*e [!_]*é uma lista classificada lexicograficamente.
Gilles 'SO- stop be evil'
11
@TomAuger Os argumentos para lssão classificados (em dois grupos: os que começam com _e os outros) quando são gerados pelo shell. Corra echo ls -lf _* [!_]*para ver o que acontece. A -fbandeira diz lspara não fazer nenhuma classificação.
Gilles 'SO- stop be evil'
16

Se você não deseja misturar letras minúsculas e maiúsculas, defina seu código do idioma como C, que recebe os caracteres na ordem numérica. _cai entre maiúsculas e minúsculas.

$ LC_COLLATE=C ls    
BAR  FOO  _score  _under  hello  world
$ LC_COLLATE=en_US ls                    
BAR  FOO  hello  _score  _under  world

As configurações de localidade LC_MESSAGES(idioma das mensagens de erro), LC_CTYPE(conjuntos de caracteres) e LC_TIME(formato de data e hora) são muito úteis. LC_COLLATEe LC_NUMERICgeralmente são mais problemáticos do que valem, não recomendo configurá-los. A classificação lexicográfica adequada é mais complicada do que LC_COLLATEdeveria ser especificada e pode causar todo tipo de comportamento estranho quando você usa intervalos de caracteres em expressões regulares. LC_NUMERICé principalmente cosmético, exceto quando algo dá terrivelmente errado, porque algum programa produziu um número com um separador decimal diferente de ..

Gilles 'SO- parar de ser mau'
fonte
+1 muito interessante. Então, usando este formulário, você está configurando temporariamente a variável de ambiente LC_COLLATE apenas para essa instância de ls? Isso esta certo?
Tom Auger
11
Alguma maneira de fazer com que os sublinhados apareçam ANTES das letras maiúsculas?
Tom Auger
11
@TomAuger Sim, VAR=value cmdconjuntos VARpara valueapenas no ambiente de cmde não toca o valor (ou ausência de valor) no shell onde você executá-lo. Para fazer o sublinhado aparecer antes de maiúsculas, você precisa definir suas próprias configurações de localidade. Isso é possível, mas difícil de usar, porque pelo menos no Linux, a biblioteca padrão procura apenas definições de localidade /usr/lib/locale- não há ~/.localevariável de ambiente ou onde você possa en_tomdefinir sua configuração.
Gilles 'SO- stop be evil'
@ TomAuger Se este é apenas um lscomando, siga a sugestão de Mikel .
Gilles 'SO- stop be evil'
2

Infelizmente, o Linux usa glibc para suas informações de localidade, não para ICU; portanto, não há como aplicá-lo diretamente no Linux sem gastar muito esforço, atualizando a ICU na glibc ou suplementando as informações de localidade na glibc.

Ignacio Vazquez-Abrams
fonte
-4

A adição do -finterruptor (sem classificação) fez com que ele fosse mostrado dessa maneira para mim.

man ls

[root@dusknoir ~/java/test]# ls -fl
total 0
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 _1
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 _2
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 _3
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 1
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 2
-rw-r--r--  1 root  wheel  0 Jun  1 13:27 3
Tim
fonte
6
Só porque é assim que eles são armazenados no sistema de arquivos.
Ignacio Vazquez-Abrams
3
Desculpe, mas esta resposta está completamente errada. Teste: touch 3 1 _1 _3 2 _2 && ls -flsaídas2 . 1 3 _2 _3 .. _1
Marco