Como uso o cut para separar por vários espaços em branco?

23

Gostaria de obter a última coluna desta amostra:

[  3]  1.0- 2.0 sec  1.00 MBytes  8.39 Mbits/sec
[  3]  2.0- 3.0 sec   768 KBytes  6.29 Mbits/sec
[  3]  3.0- 4.0 sec   512 KBytes  4.19 Mbits/sec
[  3]  4.0- 5.0 sec   256 KBytes  2.10 Mbits/sec
...

Se eu usar

cut -d\  -f 13

eu recebo

Mbits/sec
6.29
4.19
2.10

porque às vezes há espaços adicionais no meio.

rubo77
fonte
A última coluna é Mbits/sec: é isso que você deseja ou as 2 últimas colunas?
terdon
1
Eu só quero começar a 2ª última coluna, apenas os números
rubo77

Respostas:

17

Para responder sua pergunta literalmente:

sed 's/   */:/g' | cut -d : -f 5

ou

awk -F '  +' '{print $5}'

Mas isso não acontece se o número entre colchetes atingir 10, etc. Se você estiver interessado apenas nos números, poderá remover todo o resto.

sed 's/[^.0-9][^.0-9]*/:/g' | cut -d : -f 6
Gilles 'SO- parar de ser mau'
fonte
Sim, com certeza apenas os números, mas apenas a sua 3ª exemplo funciona corretamente
rubo77
@ rubo77 Funciona para mim. Os dois primeiros exemplos fazem exatamente o que você pede no seu título. Ou você também queria retirar a unidade? Nesse caso, adicione | sed 's/ .*//'no final dos dois primeiros exemplos. Claro que existem muitas outras maneiras de fazer isso.
Gilles 'SO- stop be evil'
um pouco mais curto com em +vez de *: teste do gato | sed 's / [^. 0-9] \ + /: / g' | corte -d: -f 6
rubo77
@ rubo77 Se o seu sed suporta, é claro. É suportado pelo GNU e BusyBox, mas não por, por exemplo, BSD ou Solaris. O POSIX especifica +e ?no ERE, mas deixa \+e \?no BRE indefinido.
Gilles 'SO- stop be evil' em
22

Se usarmos o trcomando junto com a opção squeeze ( -sflag) para converter todos os vários espaços consecutivos em um único espaço e, em seguida, executar a cutoperação com espaço como delimitador - podemos acessar a coluna necessária que contém os números.

Consulte o código abaixo:

cat file | tr -s ' ' | cut -d ' ' -f 8

Wald Schilfrohr
fonte
4
Essa resposta deve ser maior; é de longe a solução mais simples e legível.
Luke Davis
5

Todos esses comandos imprimirão a última coluna de um arquivo separado por espaço:

  • awk '{print $NF}' file

    in awk, NFé o número de campos e $NFé o último campo.

  • perl -lane 'print $F[$#F]' file

    -adivide o arquivo no espaço em branco na matriz @F, $#Fé o número de elementos na matriz, assim $F[$#F]como o último elemento. Os -nmeios leem o arquivo fornecido na linha de comando e aplicam o script passado -ea cada linha. -lapenas adiciona um caractere de nova linha ( \n) a cada printinstrução.

  • sed 's/.* //g'

    uma expressão regular simples que combina tudo com o último espaço e o exclui, deixando apenas a última coluna.

  • rev file | cut -d' ' -f 1 | rev

    revinverte sua saída para que o último campo seja o primeiro, cutcom espaço delimitador para imprimi-lo e revreverter o texto de volta ao normal. Isso não funcionará se você tiver espaços em branco consecutivos .

Com base em suas informações, acho que você não quer a última coluna, mas a penúltima ou as duas últimas. Nesse caso, use-os para imprimir os últimos 2 ( 8.39 Mbits/sec):

awk '{print $(NF-1),$NF}' file 
perl -lane 'print "$F[$#F-1] $F[$#F]"' file 
sed 's/.* \(.* .*\)/\1/' file 
rev file | cut -d' ' -f 1,2 | rev

e estes para imprimir o penúltimo ( 8.39):

awk '{print $(NF-1)}' file 
perl -lane 'print $F[$#F-1]' file 
sed 's/.* \(.*\) .*/\1/' file 
rev file | cut -d' ' -f 2 | rev
terdon
fonte
4

Você não pode separar várias ocorrências de espaços em branco usando o cutmanual:

Os campos de saída são separados por uma única ocorrência do caractere delimitador de campo.

a menos que o texto seja separado pela mesma quantidade ou você use trpara remover o excesso deles.

Caso contrário, use ferramentas alternativas, como awk, sedou ex.

Por exemplo:

ex -s +'%norm $2Bd0' +%p +q! foo.txt

Substitua +q!por -cwqpara salvar as alterações no local.

kenorb
fonte
0

Use um liner perl da seguinte maneira:

perl -lane 'print $F[-2]' input_file

Explicação:

A opção -efaz com que o intérprete perl procure o script embutido, e não em um arquivo.

A opção -nfaz com que a entrada (arquivo ou STDIN de um canal) seja lida linha por linha.

A opção -lremove o separador de registros de entrada (dependente do SO, nova linha no UNIX por padrão) depois de ler a linha e a adiciona no final de cadaprint

A opção -afaz com que cada linha de entrada seja dividida em espaço em branco na matriz @Fe $F[-2]é o segundo elemento contado a partir do final, que é o campo que você deseja. Você também pode usar $F[$#F-1], onde $#Festá o último índice da matriz @F, que é um pouco menos legível.

Timur Shtatland
fonte