Como fazer o comando 'cut' tratar os mesmos delimitadores sequenciais como um?

309

Estou tentando extrair um determinado (o quarto) campo do fluxo de texto baseado em coluna e ajustado por 'espaço'. Estou tentando usar o cutcomando da seguinte maneira:

cat text.txt | cut -d " " -f 4

Infelizmente, cutnão trata vários espaços como um delimitador. Eu poderia ter passado pelo awk

awk '{ printf $4; }'

ou sed

sed -E "s/[[:space:]]+/ /g"

para recolher os espaços, mas eu gostaria de saber se existe alguma maneira de lidar cute vários delimitadores nativamente?

mbaitoff
fonte
12
AWK é o caminho a percorrer.
Pausado até novo aviso.
Possível duplicata da ajuda de corte
Inanc Gumus

Respostas:

546

Experimentar:

tr -s ' ' <text.txt | cut -d ' ' -f4

Na trpágina do manual:

-s, --see squeeze-repeat substitui cada sequência de entrada de um caractere repetido
                        listado no SET1 com uma única ocorrência
                        desse personagem
kev
fonte
24
Não há necessidade de cataqui. Você poderia passar < text.txtdiretamente para tr. pt.wikipedia.org/wiki/Cat_%28Unix%29#Useless_use_of_cat
arielf
1
Não tenho certeza de que é mais simples, mas como você irá mesclar, pode renunciar aos recortes -de traduzir diretamente de vários caracteres para a guia. Por exemplo: eu vim aqui procurando uma maneira de exportar automaticamente minha exibição:who am i | tr -s ' ()' '\t' | cut -f5
Leo
Isso não remove os espaços em branco iniciais / finais (que podem ou não ser desejados, mas geralmente não são), em contraste com a solução awk. A solução awk também é muito mais legível e menos detalhada.
N
-1 AVISO: NÃO É A MESMA COISA QUE TRATA DELIMETERS SEQUENCIAIS COMO UM. Compare echo "a b c" | cut -d " " -f2-,echo "a b c" | tr -s " " | cut -d " " -f2-
user541686
96

Como você comenta sua pergunta, awké realmente o caminho a percorrer. cutÉ possível usar junto com tr -sespremer espaços, como mostra a resposta de kev .

Permitam-me, no entanto, examinar todas as combinações possíveis para futuros leitores. As explicações estão na seção Teste.

tr | cortar

tr -s ' ' < file | cut -d' ' -f4

awk

awk '{print $4}' file

festança

while read -r _ _ _ myfield _
do
   echo "forth field: $myfield"
done < file

sed

sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' file

Testes

Dado este arquivo, vamos testar os comandos:

$ cat a
this   is    line     1 more text
this      is line    2     more text
this    is line 3     more text
this is   line 4            more    text

tr | cortar

$ cut -d' ' -f4 a
is
                        # it does not show what we want!


$ tr -s ' ' < a | cut -d' ' -f4
1
2                       # this makes it!
3
4
$

awk

$ awk '{print $4}' a
1
2
3
4

festança

Isso lê os campos sequencialmente. Ao usar _, indicamos que essa é uma variável descartável como uma "variável indesejada" para ignorar esses campos. Dessa forma, armazenamos $myfieldcomo o quarto campo no arquivo, independentemente dos espaços entre eles.

$ while read -r _ _ _ a _; do echo "4th field: $a"; done < a
4th field: 1
4th field: 2
4th field: 3
4th field: 4

sed

Isso captura três grupos de espaços e sem espaços ([^ ]*[ ]*){3}. Então, ele captura o que quer que chegue até um espaço como o quarto campo, com o qual finalmente é impresso \1.

$ sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' a
1
2
3
4
fedorqui 'Então pare de prejudicar'
fonte
2
awkAlém de elegante e simples, ele também está incluído no VMware ESXi, onde trestá ausente.
User121391
2
@ user121391 ainda outro motivo para usar awk!
fedorqui 'SO stop prejudying'
@fedorqui Eu nunca ouvi falar do sublinhado como "variável lixo". Você pode fornecer mais informações / referências sobre isso?
BryKKan
1
@BryKKan Aprendi sobre isso no Greg's Como posso ler um arquivo (fluxo de dados, variável) linha por linha (e / ou campo por campo)? : Algumas pessoas usam a variável descartável _ como uma "variável indesejada" para ignorar os campos. Ela (ou de fato qualquer variável) também pode ser usada mais de uma vez em um único readcomando, se não nos importarmos com o que é necessário . Pode ser qualquer coisa, é só que de alguma forma se tornou padrão em vez de junk_varou whatever:)
fedorqui 'Então pare de prejudicar'
25

solução mais curta / mais amigável

Depois de ficar frustrado com as muitas limitações de cut, escrevi meu próprio substituto, que pedi cuts"cortar com esteróides".

cortes fornece a provável solução mais minimalista para esse e muitos outros problemas relacionados a cortar / colar.

Um exemplo, dentre muitos, abordando essa questão em particular:

$ cat text.txt
0   1        2 3
0 1          2   3 4

$ cuts 2 text.txt
2
2

cuts apoia:

  • detecção automática dos delimitadores de campo mais comuns em arquivos (+ capacidade de substituir os padrões)
  • delimitadores correspondentes a vários caracteres, caracteres mistos e regex
  • extraindo colunas de vários arquivos com delimitadores mistos
  • compensações do final da linha (usando números negativos), além do início da linha
  • colagem automática de colunas lado a lado (não é necessário chamar pasteseparadamente)
  • suporte para reordenação de campo
  • um arquivo de configuração em que os usuários podem alterar suas preferências pessoais
  • grande ênfase na facilidade de uso e digitação minimalista necessária

e muito mais. Nada disso é fornecido por padrão cut.

Consulte também: https://stackoverflow.com/a/24543231/1296044

Fonte e documentação (software livre): http://arielf.github.io/cuts/

arielf
fonte
4

Este one-liner do Perl mostra o quanto o Perl está relacionado ao awk:

perl -lane 'print $F[3]' text.txt

No entanto, a @Fmatriz de divisão automática inicia no índice, $F[0]enquanto os campos awk começam com$1

Chris Koknat
fonte
3

Nas versões que cuteu conheço, não, isso não é possível. cuté útil principalmente para analisar arquivos em que o separador não é um espaço em branco (por exemplo /etc/passwd) e possui um número fixo de campos. Dois separadores seguidos significam um campo vazio, e isso também vale para espaços em branco.

Benoit
fonte