Como usar um comando shell para mostrar apenas a primeira e a última coluna em um arquivo de texto?

Preciso de ajuda para descobrir como usar o comando sed para mostrar apenas a primeira e a última coluna em um arquivo de texto. Aqui está o que eu tenho até agora para a coluna 1:

cat logfile | sed "s/\|/ /"|awk "{print $1}" 

Minha tentativa frágil de fazer a última coluna aparecer também foi:

cat logfile | sed "s/\|/ /"|awk "{print $1}{print $8}" 

No entanto, isso pega a primeira e a última coluna e as mescla em uma lista. Existe uma maneira de imprimir a primeira e as últimas colunas claramente com os comandos sed e awk?

Exemplo de entrada:

foo|dog|cat|mouse|lion|ox|tiger|bar 

Comentários

  • Forneça alguns exemplos de entrada.

Resposta

Quase lá. Basta colocar as referências das duas colunas uma ao lado da outra.

cat logfile | sed "s/|/ /" | awk "{print $1, $8}" 

Observe também que você não precisa cat aqui .

sed "s/|/ /" logfile | awk "{print $1, $8}" 

Observe também que você pode dizer awk que os separadores de coluna são |, em vez de espaços em branco, então você não precisa sed também.

awk -F "|" "{print $1, $8}" logfile 

De acordo com as sugestões de Caleb , se você quiser uma solução que ainda produza o último campo , mesmo se não houver exatamente oito, você pode usar $NF.

awk -F "|" "{print $1, $NF}" logfile 

Além disso, se quiser saída para reter os | separadores, em vez de usar um espaço, você pode especificar os separadores de campo de saída. Infelizmente, é “um pouco mais desajeitado do que apenas usar a sinalização -F, mas aqui estão três abordagens.

  • Você pode atribuir a entrada e separadores de campo de saída no próprio awk, no bloco BEGIN.

    awk "BEGIN {FS = OFS = "|"} {print $1, $8}" logfile 
  • Você pode atribuir essas variáveis ao chamar awk na linha de comando, por meio do sinalizador -v.

    awk -v "FS=|" -v "OFS=|" "{print $1, $8}" logfile 
  • ou simplesmente:

    awk -F "|" "{print $1 "|" $8}" logfile 

Comentários

  • Bom trabalho detalhando como este problema pode ser simplificado. Você pode adicionar uma observação sobre como usar | como um separador de saída em vez de o espaço padrão para concatenação de string. Você também pode explicar para usar $NF em vez de codificação permanente $8 para obter a última coluna.
  • depois disso, como atualizar o arquivo?
  • @pankajprasad Grave em um novo arquivo com h > então sobrescreva o antigo ou use sponge. Esta é realmente uma questão nova.
  • @Sparhawk funciona, mas a expansão do conteúdo é apagada. como lidar com isso?
  • @pankajprasad Você precisa fazer uma nova pergunta. Clique no grande botão azul no topo que diz ” Faça uma pergunta “.

Resposta

Você está usando awk de qualquer maneira:

awk "{ print $1, $NF }" file 

Comentários

  • Não ‘ você precisaria especificar o separador de campo de entrada (já que, neste caso, parece seja | em vez desse espaço) com -F\| ou semelhante? E se ele quisesse usar o mesmo delimitador para a saída?
  • @Caleb Provavelmente: estava esperando o OP confirmar como exatamente se parecia a entrada, em vez de tentar suposição com base nos exemplos que não funcionam …
  • Observe que isso pressupõe que a entrada contém pelo menos 2 campos.
  • @St é phaneChazelas OP afirmou claramente no código que tem oito campos, sempre.
  • @ michaelb958 Acho ” claramente ” está exagerando, só um pouco 🙂

Resposta

Basta substituir do primeiro ao último | com um | (ou espaço se preferir):

sed "s/|.*|/|/" 

Observe que embora não haja sed implementação em que | seja especial (desde que estendido regular expressões não são ativadas por meio de -E ou em algumas implementações), o próprio \| é especial em alguns como o GNU sed. Portanto, você não deve escapar | se pretende que ele corresponda ao caractere |.

Se substituir por espaço e se a entrada já puder conter linhas com apenas um |, então, você “terá que tratar isso especialmente como |.*| não correspondeu àqueles.Isso pode ser:

sed "s/|\(.*|\)\{0,1\}/ /" 

(ou seja, tornar a .*| parte opcional) Ou:

sed "s/|.*|/ /;s/|/ /" 

ou:

sed "s/\([^|]*\).*|/\1 /" 

Se você deseja o primeiro e o oitavo campos, independentemente do número de campos em a entrada, então é apenas:

cut -d"|" -f1,8 

(todos esses funcionariam com qualquer utilitário compatível com POSIX assumindo a entrada forma texto válido (em particular, os sed geralmente não funcionarão se a entrada tiver bytes ou sequências de bytes que não formem caracteres válidos no local atual, como por exemplo printf "unix|St\351phane|Chazelas\n" | sed "s/|.*|/|/" em um local UTF-8)).

Resposta

Se você se sentir sem dificuldade e sem sed, poderá alcançar o mesma coisa com coreutils:

paste <( cut -d"|" -f1 file) \ <(rev file | cut -d"|" -f1 | rev) 

Comentários

  • cut é mais limpo e compacto do que awk / sed quando você está apenas interessado na primeira coluna, ou se os delimitadores são fixos (ou seja, não é um número variável de espaços).
  • Muito elegante!

Resposta

Parece que você está tentando obter o primeiro e o último campos de texto delimitados por |.

Presumi que seu arquivo de registro contém o texto abaixo,

foo|dog|cat|mouse|lion|ox|tiger|bar bar|dog|cat|mouse|lion|ox|tiger|foo 

E você deseja a saída como,

foo bar bar foo 

Se sim, então aqui vem o comando para o seu “s

Através do GNU sed,

sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" file 

Exemplo:

$ echo "foo|dog|cat|mouse|lion|ox|tiger|bar" | sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" foo bar 

Comentários

  • As colunas não são delimitadas por uma barra vertical | mas eles estão em colunas, estou interessado em usar sed, mas não usando o comando awk como você fez em seu comando: sed -r ‘ s ~ ^ ([^ |] *) . * \ | (. *) $ ~ \ 1 \ 2 ~ ‘ arquivo
  • ” As colunas são não delimitado por um tubo | mas eles estão em colunas “, você quer dizer que as colunas são separadas por espaços?
  • Um exemplo de entrada e saída seria melhor.

Resposta

Você provavelmente deveria fazer isso com sed – Eu faria de qualquer maneira – mas, apenas porque ninguém escreveu este ainda:

while IFS=\| read col1 cols do printf %10s%-s\\n "$col1 |" " ${cols##*|}" done <<\INPUT foo|dog|cat|mouse|lion|ox|tiger|bar INPUT 

SAÍDA

 foo | bar 

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *