Obter lista delimitada por vírgula de iniciais de itens no diretório?

2

Como posso gerar uma lista, delimitada por vírgulas e sem distinção entre maiúsculas e minúsculas, dos primeiros caracteres dos nomes dos arquivos e diretórios em um diretório, excluindo inicial "." itens, sem duplicatas? Eu não preciso que seja recursivo - apenas um nível de profundidade.

Por exemplo, de um diretório onde ls produz…

drwxr-xr-x+ 10 bryan  staff   340B Jun  6 15:32 .
drwxrwx---@ 27 bryan  staff   918B Jun  6 15:29 ..
-rw-r--r--@  1 bryan  staff   6.0K Jun  6 15:32 .secrets
drwxr-xr-x+  2 bryan  staff    68B Jun  6 15:30 Apoptosis
drwxr-xr-x+  2 bryan  staff    68B Jun  6 15:32 Fanciful Notions
-rwxr-x---@  1 bryan  staff   351B Jun  2 16:57 Pungent
-rwxr-x---@  1 bryan  staff   351B Jun  2 16:57 Zoophilia
-rwxr-x---@  1 bryan  staff   351B Jun  2 16:57 addled_symbionts
-rwxr-x---@  1 bryan  staff   351B Jun  2 16:57 putrid
drwxr-xr-x+  2 bryan  staff    68B Jun  6 15:30 zuegma mandegreen

… eu gostaria de voltar…

a, f, p, z

Estou usando o BSD, sou um nube e não consigo fazer isso funcionar.

    
por Bryan 07.06.2015 / 00:41

5 respostas

3

Você pode ir com

ls -1 |  cut -b1 | tr '[:upper:]' '[:lower:]' | sort -u | paste -d, -s

onde:

  • ls -1 fornece uma lista de nomes de arquivos (um por linha),
  • cut -b1 leva apenas o primeiro caractere por linha,
  • tr '[:upper:]' '[:lower:]' transforma todos no limite inferior,
  • sort -u remove a duplicata e
  • paste -d, -s coloca as linhas juntas usando , como separador.
por 07.06.2015 / 01:08
3

Você poderia fazer isso com o shell / coreutils:

for f in *; do printf "%s\n"  "${f:0:1}" ; done | 
    tr '[A-Z]' '[a-z]' | sort | uniq | paste -d, -s

A sintaxe ${var:X:Y} imprime uma substring longa em caracteres Y da variável $var a partir da posição X

    
por 07.06.2015 / 01:08
3
printf %c,\n * | 
sort -fu        |
dd cbs=8 conv=lcase,block

... vai ...

  1. imprime o primeiro caractere de cada argumento correspondido no * glob seguido por uma vírgula e um \n ewline para stdout
  2. classifica esse fluxo ignorando maiúsculas e minúsculas e apertando duplicatas
  3. dobre esse fluxo em uma única linha de 8 (espaço-preenchido) caracteres por registro enquanto simultaneamente converte todos os caracteres maiúsculos em minúsculas

Eu acho que tenho alguns nomes de arquivos estranhos neste diretório que precisam ser removidos, mas ...

0,      1,      =,      a,      b,      c,      d,      e,      f,      g,      h,      i,      k,      l,      m,      n,      o,      p,      q,      r,      s,      t,      w,      x,      y,      z,      _,      ~,      
0+1 records in
0+1 records out
224 bytes (224 B) copied, 7.2813e-05 s, 3.1 MB/s

O último bit é o relatório de processamento de dd . Você pode ver que é bem rápido. Você pode descartar o relatório com 2>/dev/null como quiser.

Opcionalmente, adicione outro dd ou fold ou algo na ponta do pipeline para reinar no comprimento da linha. Como:

CMD | dd cbs=80 conv=unblock

... ou ...

CMD | fold -w80

... que diferem apenas um pouco - dd removerá espaços à direita dos resultados dobrados em limites de 80 bytes - o que deve render no máximo 10 resultados por linha em 74 bytes por linha, enquanto fold interpretará caracteres como chars (não bytes) , mas também interpretam backspaces e tabulações de maneiras sensíveis à coluna sem remover espaços à direita.

Os resultados duplicados de% p_de dd foram transmitidos por sed -n l :

0,      1,      =,      a,      b,      c,      d,      e,      f,      g,$
h,      i,      k,      l,      m,      n,      o,      p,      q,      r,$
s,      t,      w,      x,      y,      z,      _,      ~,$
    
por 07.06.2015 / 03:25
3

Apenas para o registro; uma solução somente shell com ksh ( ksh93 necessário aqui) ou (versões mais recentes de) bash se todos os processos externos devem ser evitados:

typeset -A a
for file in *
do typeset -l f=${file:0:1} ; a+=( [$f]= )
done
list=$( printf ", %s" "${!a[@]}" )
printf "%s" "${list#, }"
    
por 07.06.2015 / 02:48
0
#!/usr/bin/awk -f
BEGIN {
  OFS = ", "
  for (z in ARGV)
    y[tolower(substr(ARGV[z], 1, 1))]
  for (x in y)
    $(++w) = x
  print
}

Ligue assim

hello.awk *
    
por 07.06.2015 / 08:30