mostra apenas o arquivo de origem e o arquivo vinculado de destino usando 'ls'

10

Eu posso mostrar o arquivo de destino para o qual um link aponta para usar ls -l :

snowch$ ls -l /usr/local/bin/mvn
lrwxr-xr-x  1 snowch  admin  29 12 Dec 08:58 /usr/local/bin/mvn -> ../Cellar/maven/3.2.3/bin/mvn

Existe uma maneira de mostrar menos resultados sem ter que passar por outro comando como o awk? Por exemplo:

snowch$ ls ?? /usr/local/bin/mvn
/usr/local/bin/mvn -> ../Cellar/maven/3.2.3/bin/mvn

Estou executando o 3.2.53 no OS X 10.9.5. A saída de vários comandos é mostrada abaixo:

snowch$ ls -H /usr/local/bin/mvn
/usr/local/bin/mvn

snowch$ ls -L /usr/local/bin/mvn
/usr/local/bin/mvn

snowch$ file /usr/local/bin/mvn
/usr/local/bin/mvn: POSIX shell script text executable

snowch$ file -b /usr/local/bin/mvn
POSIX shell script text executable
    
por Chris Snow 12.12.2014 / 10:31

4 respostas

7

ls infelizmente não tem uma opção para recuperar atributos de arquivo e exibi-los de maneira arbitrária. Alguns sistemas possuem comandos separados para isso (por exemplo, o GNU tem um comando stat ou a funcionalidade no GNU find ).

Na maioria dos sistemas modernos, com a maioria dos arquivos, isso deve funcionar:

$ ln -s '/foo/bar -> baz' the-file
$ LC_ALL=C ls -ldn the-file | sed '
   1s/^\([^[:blank:]]\{1,\}[[:blank:]]\{1,\}\)\{8\}//'
the-file -> /foo/bar -> baz

Isso funciona removendo os primeiros 8 campos delimitados em branco da primeira linha da saída de ls -l . Isso deve funcionar, exceto em sistemas onde o gid não é exibido ou os dois primeiros campos são unidos quando há um grande número de links.

Com o GNU stat :

$ LC_ALL=C stat -c '%N' the-file
'the-file' -> '/foo/bar -> baz'

Com o GNU find :

$ find the-file -prune \( -type l -printf '%p -> %l\n' -o -printf '%p\n' \)
the-file -> /foo/bar -> baz

Com o stat do FreeBSD / OS / X:

f=the-file
if [ -L "$f" ]; then
  stat -f "%N -> %Y" -- "$f"
else
  printf '%s\n' "$f"
fi

com zsh stat:

zmodload zsh/stat
f=the-file
zstat -LH s -- "$f"
printf '%s\n' ${s[link]:-$f}

Muitos sistemas também têm um comando readlink para obter especificamente o destino de um link:

f=the-file
if [ -L "$f" ]; then
  printf '%s -> ' "$f"
  readlink -- "$f"
else
  printf '%s\n' "$f"
fi
    
por 12.12.2014 / 11:33
5

Use o comando file .

[sreeraj@server ~]$ ls -l mytest
lrwxrwxrwx 1 sreeraj sreeraj 15 Dec 12 09:31 mytest -> /usr/sbin/httpd

[sreeraj@server ~]$ file mytest
mytest: symbolic link to '/usr/sbin/httpd'

ou

[sreeraj@server ~]$ file -b mytest
symbolic link to '/usr/sbin/httpd'
[sreeraj@server ~]$

Além disso, leia a man page de ls e verifique as opções -L e -H e veja se isso seria suficiente para sua exigência.

    
por 12.12.2014 / 10:40
2

Com um GNU ls pelo menos (e, aparentemente, tcsh da implementação) você pode hackear a variável de ambiente $LS_COLORS para inserir delimitadores onde você gosta (mas tcsh incorporados ls-F não vinculam alvos - apenas sinalizadores de link ) Geralmente ls insere fugas de terminal não imprimíveis arbitrárias com base nos valores armazenados dentro daquele ambiente var, mas não há nada que nos impeça de inserir qualquer outra coisa arbitrária. Mais sobre este aqui .

Por exemplo:

LS_COLORS='ln=///\n:lc=:no=//:rc=:rs=:' \
\ls ~ -l --color=always | 
sed '\|///|,\|//|!d;//d'

Isso coloca uma string como // na cabeça de todas as listagens (logo antes de lrwcrwx ) e um ///\n antes do nome do arquivo de qualquer link. sed , em seguida, filtra os intervalos de linha - irá d excluir cada linha de entrada até encontrar /// e, a partir daí, até a próxima linha que corresponder a // , excluirá linhas correspondentes a // . Por isso, só obtém o nome do link e o destino do link, independentemente dos caracteres intervenientes. Isso ocorre porque / não pode ocorrer em um nome de arquivo - e aqueles em qualquer caminho que ls possa imprimir só ocorrerão individualmente.

Veja?

mkdir test; cd test
touch 'long


name' shortname
ln -s l* "$(printf %s.ln l*)"; ln -s s* shortname.ln

LS_COLORS='ln=///\n:lc=:no=//:rc=:rs=:' \
\ls  -l --color=always | sed '\|///|,\|//|!d;//d'

... que imprime:

long


name.ln -> long


name
shortname.ln -> shortname

Tente você mesmo.

    
por 12.12.2014 / 12:28
-1

[No Linux / Bash]

Eu faria isso:

ls -l | sed -e"s/ \+/ /g" | cut -d' ' -f 9-

O comando sed recolhe vários espaços para um único espaço; o cut extrai o 9º campo em diante, onde o separador de campo é um espaço.

Saída típica disso:

libboost_atomic.a
libboost_atomic.so -> libboost_atomic.so.1.57.0
libboost_atomic.so.1.57.0
...
libboost_wserialization.a
libboost_wserialization.so -> libboost_wserialization.so.1.57.0
libboost_wserialization.so.1.57.0

Alternativas são:

ls -l | awk '{ print $9, $10, $11 }'
ls -l | awk '{ $1 = $2 = $3 = $4 = $5 = $6 = $7 = $8 = "" ; print }'

Mas esses são imperfeitos: o primeiro pode produzir espaços à direita; o segundo, espaços principais.

    
por 14.07.2015 / 18:15

Tags