Tipo de arquivo e desreferencia ao listar o diretório com o comando LS

6

Estou tentando combinar argumentos com o comando ls para listar um conteúdo de diretório. O que eu estou basicamente tentando alcançar é listar o diretório desreferenciando todos os links, mas mostrando explicitamente que o item listado é um link. Eu tentei combinar as opções --dereference e --classify , mas em vez de mostrar o símbolo do link ( @ ), recebo um * , pois o link tem como alvo um arquivo executável.

Alguma ideia de como posso obter esse resultado? Estou aberto a outras alternativas que não o comando ls .

EDITAR: Eu realmente uso outras opções do comando ls . Meu comando atual junto com suas opções é o seguinte:

ls -ogq -LB --group-directories-first --time-style=long-iso

Eu pretendo analisar a saída dentro de um aplicativo que estou construindo e não posso usar a saída de link padrão com a seta ( -> ). Outros itens no diretório (por exemplo, pastas e arquivos) também devem ser listados.

EDIT (2):

Só para esclarecer, estou desenvolvendo uma aplicação Java que usa uma API SSH2 para conectar-se a servidores e diretórios de lista. O resultado da listagem é então usado para preencher uma árvore usando o plugin jsTree jQuery. Atualmente, o comando que citei acima me fornece a seguinte saída:

felipe@simba:/mnt/drive$ ls -ogq --group-directories-first --time-style=long-iso 
total 12
drwxr-sr-x 2 4096 2014-06-11 18:04 folder1
drwxr-sr-x 6 4096 2014-06-27 19:35 folder2
dr-Sr-s-wt 2 4096 2014-06-27 13:51 folderWithPermissions
-rw-r--r-- 1    0 2014-06-30 10:42 file.txt
lrwxrwxrwx 1   49 2014-06-30 11:36 linkTeste -> folder2/dir/otherfile.txt

Ao aplicar uma expressão regular, posso identificar o que é uma pasta, um arquivo ou um link, observando as permissões. Mas quando eu tenho um link, preciso listar apenas o nome do link, em vez de name -> destination . Se eu usar a opção -L para o comando ls , somente o nome do link será gerado e receberei as permissões do destino referenciado (o que é uma coisa boa), pois a opção -L desreferencia o link, mas dessa maneira posso não sei que o link é realmente um link.

felipe@simba:/mnt/drive$ ls -ogq -L --group-directories-first --time-style=long-iso 
total 12
drwxr-sr-x 2 4096 2014-06-11 18:04 folder1
drwxr-sr-x 6 4096 2014-06-27 19:35 folder2
dr-Sr-s-wt 2 4096 2014-06-27 13:51 folderWithPermissions
-rw-r--r-- 1    0 2014-06-30 10:42 file.txt
-rwxr-xr-x 1    0 2014-06-27 18:40 linkTeste

Eu preciso listar apenas o nome do link, saber que é um link e saber qual é o destino (arquivo, pasta ou link). Eu posso lidar com diferentes tipos de saída desde que eu vou aplicar uma expressão regular de qualquer maneira.

Alternativas usando find ou stat também são bem-vindas.

    
por Felipe Leão 30.06.2014 / 18:45

1 resposta

5

Editar em resposta à pergunta atualizada

Como você só se preocupa com links, diretórios e arquivos regulares, e não precisa lidar com outros tipos de arquivos que ls pode identificar (FIFOs, soquetes, etc), você poderia fazer algo como stat . Para os exemplos abaixo, criei o seguinte ambiente de teste:

$ ls -l
total 4.0K
-rw-r--r-- 1 terdon terdon    0 Jun 30 23:12 a new?line 
-rw-r--r-- 1 terdon terdon    0 Jun 30 23:12 a space
-rw-r--r-- 1 terdon terdon    0 Jun 30 23:12 a?tab
drwxr-xr-x 2 terdon terdon 4.0K Jun 30 23:11 dir1
lrwxrwxrwx 1 terdon terdon    4 Jun 30 23:13 linktodir1 -> dir1
lrwxrwxrwx 1 terdon terdon    7 Jun 30 23:13 sh -> /bin/sh

Como você pode ver, estes incluem links, links para executáveis, um nome de arquivo com um espaço, um com uma guia ( \t ) e um com uma nova linha ( \n ). A maioria desses arquivos quebraria sua abordagem ls , mas stat pode lidar com eles corretamente:

$ stat --printf "%A\t%N\t%F\n" * 
-rw-r--r--  ‘a new\nline’   regular file
-rw-r--r--  ‘a space’   regular file
-rw-r--r--  ‘a\ttab’    regular file
drwxr-xr-x  ‘dir1’  directory
lrwxrwxrwx  ‘linktodir1’ -> ‘dir1’  symbolic link
lrwxrwxrwx  ‘sh’ -> ‘/bin/sh’   symbolic link

As seções relevantes de man stat :

--printf=FORMAT

like --format, but interpret backslash escapes, and do not output a mandatory trailing newline. If you want a newline, include \n in FORMAT

%A     access rights in human readable form

%F     file type

%N     quoted file name with dereference if symbolic link

Observe que os campos são separados por \t , isso significa que você poderá lidar com espaços em branco dentro de campos (em nomes de arquivos, por exemplo) normalmente.

Você mencionou que não pode lidar com -> . Eu não tenho certeza do porquê, mas você pode simplesmente remover isso com sed

$ stat --printf "%A\t%N\t%F\n" * | sed 's/->//' 
lrwxrwxrwx  ‘linktodir1’  ‘dir1’    symbolic link

ou substituí-lo por outra string:

$ stat --printf "%A\t%N\t%F\n" * | sed 's/->/→/' | grep linktodir
lrwxrwxrwx  ‘linktodir1’ → ‘dir1’   symbolic link

ou apenas analise o tipo de arquivo.

Dependendo do que você deseja fazer, pode ser útil separar cada um dos três tipos de arquivos que você está procurando e lidar com cada um deles separadamente. Em caso afirmativo, use find 1 e sua opção -printf :

$ find ./ -maxdepth 1 -mindepth 1 -type f -printf '%M\t%P\t%l\n'  ## files
$ find ./ -maxdepth 1 -mindepth 1 -type d -printf '%M\t%P\t%l\n'  ## directories
$ find ./ -maxdepth 1 -mindepth 1 -type l -printf '%M\t%P\t%l\n'  ## links

Nesse caso, as diretivas printf são

          %M     File's permissions (in symbolic form, as for  ls).   This
                 directive is supported in findutils 4.2.5 and later.
          %P     File's  name  with  the name of the command line argument
                 under which it was found removed.
          %l     Object of symbolic link (empty string if file  is  not  a
                 symbolic link).

Você também pode combinar o acima em um único comando (usando o operador find -o ), mas permite usar -printf para imprimir uma string arbitrária dependendo do tipo de arquivo. Por exemplo:

$ find ./ -maxdepth 1 -mindepth 1 \( -type l -printf 'link:\t%M\t%P\t%l\n' \) \
-o \( -type d -printf 'dir:\t%M\t%P\n' \) \
-o \( -type f -printf 'file:\t%M\t%P\n' \) 
file:   -rw-r--r--  a?tab
file:   -rw-r--r--  a space
link:   lrwxrwxrwx  linktodir1  dir1
file:   -rw-r--r--  a new?line
dir:    drwxr-xr-x  dir1
link:   lrwxrwxrwx  sh  /bin/sh

O comando acima interpretará \t e \n corretamente se sua saída não for mostrada em um terminal. No entanto, para lidar com nomes de arquivos com novas linhas corretamente, você precisará ter cuidado ao analisar (certifique-se de que uma "linha" começa com [file|dir|link]: ) ou use printf como terminador de linha em cada chamada \n em vez de -maxdepth :

$ find ./ -maxdepth 1 -mindepth 1 \( -type l -printf 'link:\t%M\t%P\t%l
for f in *; do 
 readlink "$f" >/dev/null && echo "$(readlink -f "$f") (link)" || echo "$f";
done
' \) \ -o \( -type d -printf 'dir:\t%M\t%P
/etc (link)
foo
sample.R
sample.R~
' \) \ -o \( -type f -printf 'file:\t%M\t%P
$ ls -l
total 512116
-rw-r--r-- 1 terdon terdon    100641 Jun 30 19:10 er
lrwxrwxrwx 1 terdon terdon         5 Jun 30 19:12 etc -> /etc/
-rw-r--r-- 1 terdon terdon 524288000 Jun 30 19:10 foo
-rwxr--r-- 1 terdon terdon       353 Jun 30 15:22 sample.R
-rwxr--r-- 1 terdon terdon       249 Jun 30 14:51 sample.R~
' \)

1 -mindepth e find são extensões GNU, portanto, essa abordagem funcionará apenas para o GNU readlink .

Os seguintes foram publicados como uma solução para a primeira versão menos específica da questão. Estou deixando-os aqui, pois podem ser úteis para os outros.

  1. Shell e readlink

    $ ls -l
    total 4.0K
    -rw-r--r-- 1 terdon terdon    0 Jun 30 23:12 a new?line 
    -rw-r--r-- 1 terdon terdon    0 Jun 30 23:12 a space
    -rw-r--r-- 1 terdon terdon    0 Jun 30 23:12 a?tab
    drwxr-xr-x 2 terdon terdon 4.0K Jun 30 23:11 dir1
    lrwxrwxrwx 1 terdon terdon    4 Jun 30 23:13 linktodir1 -> dir1
    lrwxrwxrwx 1 terdon terdon    7 Jun 30 23:13 sh -> /bin/sh
    

    Exemplo de saída:

    $ stat --printf "%A\t%N\t%F\n" * 
    -rw-r--r--  ‘a new\nline’   regular file
    -rw-r--r--  ‘a space’   regular file
    -rw-r--r--  ‘a\ttab’    regular file
    drwxr-xr-x  ‘dir1’  directory
    lrwxrwxrwx  ‘linktodir1’ -> ‘dir1’  symbolic link
    lrwxrwxrwx  ‘sh’ -> ‘/bin/sh’   symbolic link
    

    O texto acima percorre todos os arquivos e diretórios sob o atual e se $f retornar bem-sucedido (se readlink -f for um link), ele será cancelado ( -f , observe que isso seguirá todos Se você deseja apenas o primeiro nível, remova o (link) ) e imprima o destino junto com $f . Se não for, apenas imprimirá ls -l .

  2. Se isso é apenas para você e não pretende ser analisado, use apenas link -> target :

    $ stat --printf "%A\t%N\t%F\n" * | sed 's/->//' 
    lrwxrwxrwx  ‘linktodir1’  ‘dir1’    symbolic link
    

    Isso indicará claramente os links com %code% .

por 30.06.2014 / 19:22