@Jefromi - também cutnão tem regexes antes de {}ações, e é muito mais burro com delimitadores de campo (número variável de espaços?), E você tem que especificá-los manualmente. Acho que o OP queria ouvir sobre algum shift Ncomando, que não existe. O mais próximo é $1="";$2="";(...);print}, mas no meu caso deixa alguns espaços à esquerda (provavelmente separadores).
Tomasz Gandor
Respostas:
50
Uma solução que não adiciona espaço em branco extra à esquerda ou à direita :
A resposta de EdMorton não funcionou para mim (bash 4.1.2 (1) -release, GNU Awk 3.1.7 ou bash 3.2.25 (1) -release, GNU Awk 3.1.5), mas encontrada aqui de outra forma:echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch
1
@elysch não, isso não funcionará em geral, apenas parece funcionar dados alguns valores de entrada específicos. Veja o comentário que adicionei abaixo do seu comentário em minha resposta.
Ed Morton
1
Oi @fedorqui. Minha resposta é a primeira. Em minha resposta original, eu estava explicando por que a outra resposta não estava correta (espaço em branco extra à esquerda ou à direita). Algumas pessoas propuseram melhorias nos comentários. Pedimos ao OP que escolhesse uma resposta mais correta e ele escolheu a minha. Depois de alguns outros colaboradores terem editado minha resposta para fazer referência a essa resposta (veja o histórico). Está claro para você? O que você me aconselha para melhorar a compreensão da minha resposta? Saúde ;-)
olibre
1
Você está absolutamente certo e lamento muito o meu mal-entendido. Eu li a resposta rapidamente e não percebi sua resposta original (sim, eu li muito rápido). +1 para a própria resposta usando o bom truque para fazer um loop até NF-1 e depois imprimir o último elemento para evitar os espaços em branco extras. E desculpe novamente! (removerá meu comentário em um ou dois dias, para evitar mal-entendidos de leitores futuros).
fedorqui 'ASSIM, pare de prejudicar'
1
Eu usaria algum tipo de cabeçalho: <sua resposta> e, em seguida, uma regra horizontal seguida por um grande título "comparação das outras respostas". Caso contrário, mova esta comparação para outra resposta, já que aparentemente as pessoas tendem a preferir respostas curtas em uma visão "me dê meu código"
provavelmente melhor usar "NF" do que "13" no último exemplo.
glenn jackman
2
2 cenários que cabem ao OP decidir. se 13 for o último campo, usar NF está certo. Caso contrário, usar 13 é apropriado.
ghostdog74
3
2 ° precisa excluir 3 cópias do OFS do início de $ 0. 3º seria melhor com printf "%s ",$i, já que você não sabe se $ipode conter %sou algo semelhante. Mas isso imprimiria um espaço extra no final.
Isso é bom por causa de sua dinâmica. Você pode adicionar colunas no final e não reescrever seus scripts.
MinceMan
1
Isso demonstra o problema exato com que a pergunta está tentando lidar, basta fazer o oposto. Que tal imprimir o do 100º campo? Nota para mencionar que você não lida com NFisso deixando de liderar OFS.
Chris Seymour
24
A maneira correta de fazer isso é com um intervalo RE, porque ele permite que você simplesmente informe quantos campos devem ser ignorados e retém o espaçamento entre campos para os campos restantes.
por exemplo, para pular os 3 primeiros campos sem afetar o espaçamento entre os campos restantes, dado o formato de entrada que parecemos estar discutindo nesta questão é simplesmente:
Se você tem um FS que é um RE que você não pode negar em um conjunto de caracteres, você pode convertê-lo em um único caractere primeiro (RS é ideal se for um único caractere, pois um RS NÃO PODE aparecer dentro de um campo, caso contrário, considere SUBSEP), em seguida, aplique a substituição do intervalo de RE e, em seguida, converta para o OFS. por exemplo, se cadeias de "." s separassem os campos:
Então você tem o mesmo problema que com todas as soluções baseadas em loop que reatribuem os campos - os FSs são convertidos em OFSs. Se isso for um problema, você precisa examinar a função patsplit () do GNU awks.
Não funcionou para mim (bash 4.1.2 (1) -release, GNU Awk 3.1.7 ou bash 3.2.25 (1) -release, GNU Awk 3.1.5) mas encontrei aqui de outra forma:echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch
2
Não, isso falhará se $ 1 ou $ 2 contiverem a string para a qual $ 3 está definido. Tente, por exemplo, echo ' That is a test' | awk '{print substr($0, index($0,$3))}'e você descobrirá que o aque é $ 3 corresponde ao ainterior Thatem $ 1. Em uma versão muito antiga do gawk como a sua, você precisa ativar os intervalos RE com o sinalizador --re-interval.
Ed Morton
2
Você está certo, não percebeu. A propósito, realmente aprecio seu comentário. Muitas vezes quis usar uma regex com "{}" para especificar o número de elementos e nunca vi "--re-interval" no homem. 1 para você.
elysch
1
1é uma condição verdadeira e, portanto, invoca a ação padrão awk de imprimir o registro atual.
Ed Morton
1
idk quão canônico é, mas eu adicionei uma resposta agora.
Ed Morton
10
Quase todas as respostas adicionam espaços iniciais, espaços finais ou algum outro problema de separação. Para selecionar a partir do quarto campo onde o separador é um espaço em branco e o separador de saída é um único espaço, usando awkseria:
Ou para colocá-los na mesma linha, atribua $ 3 a $ 1, etc. e, em seguida, altere a NF para o número correto de campos. echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) $(i-2)=$i; NF=NF-2; print $0 }'
larsr
Olá @larsr. Sua linha de comando proposta é a única resposta correta. Todas as outras respostas adicionam espaços extras (à esquerda ou à direita). Por favor, poste sua linha de comando em uma nova resposta, eu irei votar a favor ;-)
olibre
1
Olá @sudo_O, estava falando com @larsr sobre a linha de comando que ele propôs em seu comentário. Passei cerca de cinco minutos antes de descobrir o quiproco (mal-entendido). Concordo, a resposta @Vetsin insere novas linhas ( ORS) entre os campos. Bravo pela sua iniciativa (gosto da sua resposta). Saúde
olibre
3
Outra maneira de evitar o uso da instrução de impressão:
$ awk '{$1=$2=$3=""}sub("^"FS"*","")' file
No awk, quando uma condição é verdadeira, imprimir é a ação padrão.
1 para a solução semelhante ... Mas isso pode ter problemas de desempenho se filefor grande (> 10-30 KiB). Para arquivos grandes, a awksolução tem um desempenho melhor.
TrueY
3
As opções 1 a 3 apresentam problemas com vários espaços em branco (mas são simples). Essa é a razão para desenvolver as opções 4 e 5, que processam vários espaços em branco sem nenhum problema. Obviamente, se as opções 4 ou 5 forem usadas com n=0ambas, os espaços em branco à esquerda serão preservados, o que n=0significa que não haverá divisão.
Opção 1
Uma solução de corte simples (funciona com delimitadores simples):
$ echo '1 2 3 4 5 6 7 8'| cut -d' '-f4-45678
opção 2
Forçar um recálculo do awk às vezes resolve o problema (funciona com algumas versões do awk) de espaços iniciais adicionados:
NOTA: O "^ [" FS "] *" é para aceitar uma entrada com espaços à esquerda.
Opção 5
É bem possível construir uma solução que não adicione espaços em branco extras à esquerda ou à direita e preserve os espaços em branco existentes usando a função gensubdo GNU awk, como este:
Oi BZ Sua resposta é boa. Mas a opção 3 não funciona em strings que começam com um espaço (por exemplo " 1 2 3 4 5 6 7 8 "). A opção 4 é boa, mas deixe um espaço inicial usando uma string começando com um espaço. Você acha que isso pode ser corrigido? Você pode usar o comando a echo " 1 2 3 4 5 6 7 8 " | your awk script | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'fim de verificar os espaços à esquerda / meio / à direita ... Saúde;)
olibre
Olá @olibre. Que a opção 3 falhe com espaço em branco é a razão para desenvolver as opções 4 e 5. A opção 4 só deixa um espaço à esquerda se a entrada o tiver e n for definido como 0 (n = 0). Essa eu acredito ser a resposta correta quando não há seleção de campos (nada para consertar IMO). Felicidades.
Tudo certo. Obrigado pelas informações adicionais :-) Por favor, melhore sua resposta fornecendo estas informações extras :-) Saudações
olibre
Perfeito :-) Que pena que seu usuário está desativado :-(
olibre
1
Cut tem um sinalizador --complement que torna mais fácil (e rápido) excluir colunas. A sintaxe resultante é análoga ao que você deseja fazer - tornando a solução mais fácil de ler / entender. O complemento também funciona para o caso em que você deseja excluir colunas não contíguas.
A edição acima ajuda na compreensão? O objetivo é usar o sinalizador de corte de complemento. A solução deve ser uma implementação mais rápida e concisa do que as soluções baseadas em AWK ou perl. Além disso, colunas arbitrárias podem ser cortadas.
Michael Back
1
Solução Perl que não adiciona espaços em branco à esquerda ou à direita:
Como fiquei aborrecido com a primeira resposta muito votada, mas errada, encontrei o suficiente para escrever uma resposta lá, e aqui as respostas erradas estão marcadas como tal, aqui está a minha parte. Não gosto de soluções propostas, pois não vejo razão para tornar a resposta tão complexa.
Eu tenho um log onde depois de $ 5 com um endereço IP pode haver mais texto ou nenhum texto. Preciso de tudo, desde o endereço IP até o final da linha, caso haja algo depois de $ 5. No meu caso, isso está na verdade em um programa awk, não em um awk oneliner, então o awk deve resolver o problema. Quando tento remover os primeiros 4 campos usando a resposta antiga, de boa aparência e mais votada, mas completamente errada:
echo " 7 27.10.16. Thu 11:57:18 37.244.182.218 one two three"| awk '{$1=$2=$3=$4=""; printf "[%s]\n", $0}'
ele cospe uma resposta errada e inútil (acrescentei [] para demonstrar):
[37.244.182.218 one two three]
Em vez disso, se as colunas têm largura fixa até o ponto de corte e o awk é necessário, a resposta correta e bastante simples é:
echo " 7 27.10.16. Thu 11:57:18 37.244.182.218 one two three"| awk '{printf "[%s]\n", substr($0,28)}'
O %-5salinha o resultado como colunas de 5 caracteres de largura; se isso não for suficiente, aumente o número ou use %s(com um espaço) se você não se importar com o alinhamento.
Solução baseada em AWK printf que evita% problema e é única por não retornar nada (nenhum caractere de retorno) se houver menos de 4 colunas para imprimir:
cut -f3-
?cut
não tem regexes antes de{}
ações, e é muito mais burro com delimitadores de campo (número variável de espaços?), E você tem que especificá-los manualmente. Acho que o OP queria ouvir sobre algumshift N
comando, que não existe. O mais próximo é$1="";$2="";(...);print}
, mas no meu caso deixa alguns espaços à esquerda (provavelmente separadores).Respostas:
Uma solução que não adiciona espaço em branco extra à esquerda ou à direita :
Sudo_O propõe uma melhoria elegante usando o operador ternário
NF?ORS:OFS
EdMorton oferece uma solução que preserva os espaços em branco originais entre os campos:
BinaryZebra também oferece duas soluções impressionantes:
(essas soluções preservam até mesmo espaços à direita da string original)
A solução dada por larsr nos comentários é quase correta:
Esta é a versão fixa e parametrizada da solução larsr :
Todas as outras respostas antes de setembro de 2013 são boas, mas adicione espaços extras:
Exemplo de resposta adicionando espaços iniciais extras :
Exemplo de resposta adicionando espaço extra
fonte
echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
fonte
OFS
porque você não lida comNF
espaço de entrelinha nos registros.usar corte
ou se você insiste em awk e $ 13 é o último campo
outro
fonte
printf "%s ",$i
, já que você não sabe se$i
pode conter%s
ou algo semelhante. Mas isso imprimiria um espaço extra no final.Experimente isto:
fonte
NF
isso deixando de liderarOFS
.A maneira correta de fazer isso é com um intervalo RE, porque ele permite que você simplesmente informe quantos campos devem ser ignorados e retém o espaçamento entre campos para os campos restantes.
por exemplo, para pular os 3 primeiros campos sem afetar o espaçamento entre os campos restantes, dado o formato de entrada que parecemos estar discutindo nesta questão é simplesmente:
Se você deseja acomodar espaços à esquerda e não em branco, mas novamente com o FS padrão, é:
Se você tem um FS que é um RE que você não pode negar em um conjunto de caracteres, você pode convertê-lo em um único caractere primeiro (RS é ideal se for um único caractere, pois um RS NÃO PODE aparecer dentro de um campo, caso contrário, considere SUBSEP), em seguida, aplique a substituição do intervalo de RE e, em seguida, converta para o OFS. por exemplo, se cadeias de "." s separassem os campos:
Obviamente, se OFS é um único caractere E não pode aparecer nos campos de entrada, você pode reduzir isso para:
Então você tem o mesmo problema que com todas as soluções baseadas em loop que reatribuem os campos - os FSs são convertidos em OFSs. Se isso for um problema, você precisa examinar a função patsplit () do GNU awks.
fonte
echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
echo ' That is a test' | awk '{print substr($0, index($0,$3))}'
e você descobrirá que oa
que é $ 3 corresponde aoa
interiorThat
em $ 1. Em uma versão muito antiga do gawk como a sua, você precisa ativar os intervalos RE com o sinalizador--re-interval
.1
é uma condição verdadeira e, portanto, invoca a ação padrão awk de imprimir o registro atual.Quase todas as respostas adicionam espaços iniciais, espaços finais ou algum outro problema de separação. Para selecionar a partir do quarto campo onde o separador é um espaço em branco e o separador de saída é um único espaço, usando
awk
seria:Para parametrizar o campo inicial, você pode fazer:
E também o campo final:
fonte
Entrada
Resultado
fonte
fonte
echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) $(i-2)=$i; NF=NF-2; print $0 }'
ORS
) entre os campos. Bravo pela sua iniciativa (gosto da sua resposta). SaúdeOutra maneira de evitar o uso da instrução de impressão:
No awk, quando uma condição é verdadeira, imprimir é a ação padrão.
fonte
awk '{$1=$2=$3=""}sub("^"OFS"+","")' file
como o OFS, o que resta depois de alterar o conteúdo de $ 1, $ 2 e $ 3.Não acredito que ninguém ofereceu uma casca simples:
fonte
file
for grande (> 10-30 KiB). Para arquivos grandes, aawk
solução tem um desempenho melhor.As opções 1 a 3 apresentam problemas com vários espaços em branco (mas são simples). Essa é a razão para desenvolver as opções 4 e 5, que processam vários espaços em branco sem nenhum problema. Obviamente, se as opções 4 ou 5 forem usadas com
n=0
ambas, os espaços em branco à esquerda serão preservados, o quen=0
significa que não haverá divisão.Opção 1
Uma solução de corte simples (funciona com delimitadores simples):
opção 2
Forçar um recálculo do awk às vezes resolve o problema (funciona com algumas versões do awk) de espaços iniciais adicionados:
Opção 3
Imprimir cada campo formatado com
printf
dará mais controle:No entanto, todas as respostas anteriores alteram todos os FS entre os campos para OFS. Vamos construir algumas soluções para isso.
Opção 4
Um loop com sub para remover campos e delimitadores é mais portátil e não aciona uma mudança de FS para OFS:
NOTA: O "^ [" FS "] *" é para aceitar uma entrada com espaços à esquerda.
Opção 5
É bem possível construir uma solução que não adicione espaços em branco extras à esquerda ou à direita e preserve os espaços em branco existentes usando a função
gensub
do GNU awk, como este:Também pode ser usado para trocar uma lista de campos dada uma contagem
n
:Obviamente, nesse caso, o OFS é usado para separar as duas partes da linha e o espaço em branco posterior dos campos ainda é impresso.
Nota1:
["FS"]*
é usado para permitir espaços à esquerda na linha de entrada.fonte
" 1 2 3 4 5 6 7 8 "
). A opção 4 é boa, mas deixe um espaço inicial usando uma string começando com um espaço. Você acha que isso pode ser corrigido? Você pode usar o comando aecho " 1 2 3 4 5 6 7 8 " | your awk script | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
fim de verificar os espaços à esquerda / meio / à direita ... Saúde;)Cut tem um sinalizador --complement que torna mais fácil (e rápido) excluir colunas. A sintaxe resultante é análoga ao que você deseja fazer - tornando a solução mais fácil de ler / entender. O complemento também funciona para o caso em que você deseja excluir colunas não contíguas.
fonte
Solução Perl que não adiciona espaços em branco à esquerda ou à direita:
O
@F
array perl autosplit começa no índice0
enquanto os campos awk começam com$1
Solução Perl para dados delimitados por vírgulas:
Solução Python:
python -c "import sys;[sys.stdout.write(' '.join(line.split()[3:]) + '\n') for line in sys.stdin]" < file
fonte
Para mim, a solução mais compacta e compatível com o pedido é
E se você tiver mais linhas para processar, como por exemplo o arquivo foo.txt , não se esqueça de redefinir i para 0:
Obrigado ao seu fórum.
fonte
Como fiquei aborrecido com a primeira resposta muito votada, mas errada, encontrei o suficiente para escrever uma resposta lá, e aqui as respostas erradas estão marcadas como tal, aqui está a minha parte. Não gosto de soluções propostas, pois não vejo razão para tornar a resposta tão complexa.
Eu tenho um log onde depois de $ 5 com um endereço IP pode haver mais texto ou nenhum texto. Preciso de tudo, desde o endereço IP até o final da linha, caso haja algo depois de $ 5. No meu caso, isso está na verdade em um programa awk, não em um awk oneliner, então o awk deve resolver o problema. Quando tento remover os primeiros 4 campos usando a resposta antiga, de boa aparência e mais votada, mas completamente errada:
ele cospe uma resposta errada e inútil (acrescentei [] para demonstrar):
Em vez disso, se as colunas têm largura fixa até o ponto de corte e o awk é necessário, a resposta correta e bastante simples é:
que produz a saída desejada:
fonte
Encontrei essa outra possibilidade, talvez possa ser útil também ...
awk 'BEGIN {OFS=ORS="\t" }; {for(i=1; i<14; i++) print $i " "; print $NF "\n" }' your_file
Nota: 1. Para dados tabulares e da coluna $ 1 a $ 14
fonte
Use corte:
por exemplo: se você
file1
contém:car.is.nice.equal.bmw
Executar:
cut -d . -f1,3 file1
irá imprimircar.is.nice
fonte
Isso não está muito longe de algumas das respostas anteriores, mas resolve alguns problemas:
cols.sh
:Que você agora pode chamar com um argumento que será a coluna inicial:
Ou:
Este é indexado 1; se você preferir indexação zero, use
i=s + 1
.Além disso, se você gostaria de ter argumentos para o índice inicial e índice final, altere o arquivo para:
Por exemplo:
O
%-5s
alinha o resultado como colunas de 5 caracteres de largura; se isso não for suficiente, aumente o número ou use%s
(com um espaço) se você não se importar com o alinhamento.fonte
Solução baseada em AWK printf que evita% problema e é única por não retornar nada (nenhum caractere de retorno) se houver menos de 4 colunas para imprimir:
Teste:
fonte