Como seleciono um campo / coluna na saída de `ls -l`?

22

Meu objetivo é enganosamente simples (pelo menos para mim). Desejo pegar a saída de ls -lou ls -lhe selecionar apenas um campo.

Estou procurando que isso seja o mais à prova de balas possível, o que quero dizer, suponha que os nomes de arquivos possam ter um número variável de espaços, nem tudo no campo tem o mesmo comprimento etc.

Pontos de bônus por ter um script que usará o nome do campo (ou mesmo apenas um número de campo) e retornará o conteúdo do campo.

Eu quero virar

insira a descrição da imagem aqui

para dentro:

insira a descrição da imagem aqui

soandos
fonte

Respostas:

41

Tente ls -l | awk '{print $7}'.

awk seleciona colunas para que seja perfeito para esta tarefa.

Corey Whitaker
fonte
3
Conforme explicado por @ormaaj: Não confie em informações disponíveis em locais específicos com ls. O findcomando é tremendamente útil.
Paddy Landau
@PaddyLandau Como uso o comando find para imprimir um tamanho de arquivo em megabytes, como posso ls -l --block-size=M?
SurpriseDog
@ Benjamin - O lscomando não é o padrão POSIX, portanto, um script que depende lspode ser interrompido em diferentes sistemas ou mesmo ao longo do tempo. Veja a resposta de @ormaaj nesta página para mais detalhes. Uma maneira de fazer o que você pede é com um loop Bash. Aqui está um exemplo. for FILENAME in *; do FILESIZE=$(( $( stat --format=%s "${FILENAME}" ) / 1024 )); echo "${FILENAME}" ${FILESIZE}; done. Obviamente, em vez de echo, você usaria seu processamento.
Paddy Landau
@PaddyLandau Acabei canalizando a saída do comando find para a ... | xargs -d '\n' du -mqual funciona tão bem.
SurpriseDog
@ Benjamin Você pode querer olhar para a -execopção de find.
Paddy Landau
17

Nunca analise ls . Use GNU find. Ou se a portabilidade não for importante stat(1),.

find . -maxdepth 1 -printf '%Td\n'

Para ler dados que não sejam listas de nomes de arquivos linha por linha e dividir em campos, consulte: BashFAQ / 001

Não há métodos para ler com segurança uma lista de nomes de arquivos delimitada por nova linha que faça sentido na maioria das circunstâncias.

ormaaj
fonte
1

Você pode buscar a coluna específica no shell, como:

ls -al | while read perm bsize user group size month day time file; do echo $day; done

ou awkcomo mostrado na resposta do @Corey , cut -c44-45também funcionaria após o ajuste (já que lstem colunas fixas), ou qualquer outra coisa, no entanto, o principal problema é que ele não será confiável e à prova de balas (por exemplo, no Unix, pode ser $6, não $7e alterações dependendo dos argumentos), tornando-o não amigável à máquina, portanto , não é recomendável analisar o lscomando .

O melhor é usar diferentes comandos disponíveis, como findor stat, que podem fornecer opções relevantes para formatar a saída conforme necessário. Por exemplo:

$ stat -c "%x %n" *
2016-04-10 04:53:07.000000000 +0100 001.txt
2016-04-10 05:08:42.000000000 +0100 7c1c.txt

Para retornar a coluna de apenas dias de modificações, tente este exemplo:

stat -c "%x" * | while read ymd; do date --date="$ymd" "+%d"; done

Vale ressaltar que o GNU statpode ter opções diferentes para o BSD stat, por isso ainda não será à prova de balas em diferentes sistemas operacionais.

kenorb
fonte
1
+1 para mencionar que ls não deve ser analisado nem para o uso de stat. dateno entanto, está configurado incorretamente. Você deve adicionar --date=$ymd, uma vez que date, por si só irá imprimir o dia atual, mas o objetivo aqui é converter o formato de data do arquivo
Sergiy Kolodyazhnyy
O ls -la | cut -c32-33comando com total honestidade não é totalmente confiável, não apenas por causa das possíveis armadilhas dos nomes de arquivos, mas simplesmente porque depende do comprimento dos nomes de usuários e do tamanho dos arquivos. O stat -c "%x" *.*comando parece bem, mas, usando-o, *.*você o restringe apenas aos nomes de arquivos que contêm um ponto. Eu acho que a intenção era pegar também arquivos ocultos; nesse caso, você deve permitir englobamento para dotfiles antemão e usar *em vez de *.*: shopt -s dotglob; stat -c "%x" * | [...].
kos
Ah, e o que Serg disse também, você deve adicionar --date="$ymd"ao datecomando, caso contrário ele imprimirá o dia atual do mês.
kos
Obrigado pelos comentários. Abordei os problemas e forneci um exemplo inicial melhor.
kenorb