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 usesponge
. 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