Como imprimir o primeiro campo que está tendo o valor baseado no delimitador

3

O arquivo ( myfile.txt ) contém dados da seguinte forma:

abc#ab1=23
nrt#
#clb1aX
amd#322

Saída desejada:

abc
nrt
clb1ax
amd

Eu poderia fazer assim,

for i in 'cat myfile.txt' 
do 
  s1='echo $i | cut -d'#' -f1'; 
  s2='echo $i | cut -d'#' -f2'; 
  if [ "$s1" == "" ]; then 
    echo "$s2" 
  else
    echo "$s1"
  fi;
done;

Mas há alguma maneira de fazer isso sem usar for e if , como usar awk ou sed ou cut ou algo mais em uma única linha?

    
por Spike 09.05.2018 / 11:49

6 respostas

8

Solução awk curta:

awk -F'#' 'NF{ print ($1 != "" ? $1 : $2) }' file

A saída:

abc
nrt
clb1aX
amd
    
por 09.05.2018 / 11:54
2

Resposta

sed -i "/^#/ { s/#\(.*\)//; b }
        s/#.*//" myfile.txt

Ele pode ser unido em uma linha adicionando o ; após o } , mas será mais difícil lê-lo assim.

Explicação

sed -i Mantenha as alterações no arquivo, não as grave em stdout .

/^#/ - Quando sed está posicionado na linha que começa com # .

s/#\(.*\)// - Substitua a primeira ocorrência de #[everything] por [everything] .

b - Interrompa o trabalho na linha atual e comece a trabalhar no próximo.
(Impede que o comando s/#.*// seja executado).

s/#.*// - Remove a primeira ocorrência de #[everything] .
(Isso funcionará para todas as linhas, a menos que o comando anterior b tenha saído antes.)

myfile.txt Arquivo no qual sed será executado.

    
por 09.05.2018 / 12:00
1

E se você não tivesse campos com valor ou não fosse apenas na segunda coluna? então você precisaria.

awk -F'#' '{for(i=1; i<=NF; i++) if ($i != "") {print $i; break} }' infile

Dada abaixo da amostra:

abc#asd=123
nrt#
#clsdX
####
###here
acn#123

fornecerá a saída:

abc
nrt
clsdX
here
acn

Ou usando sed e cut :

cut -d'#' -f1 <(sed 's/^#\+//; /^$/d' infile )
  • O s/^#\+// remove os hashes principais # (ocorreu uma ou mais vezes)
  • O /^$/d remove a linha vazia produzida acima, em que uma linha era toda hashes ##### ou remove linhas vazias no arquivo, se houvesse alguma.
  • O cut -d'#' -f1 imprime o primeiro campo -f1 quando fileds são delimitados por um hash -d'#'

Ou sed apenas:

sed 's/^#\+//; /^$/d; s/^\([^#]*\)#.*//' infile
  • Esse s/^\([^#]*\)#.*// captura um grupo de partida começando do início da linha para qualquer coisa até que um primeiro hash seja visto e apenas imprima em resultado e ignore o restante.
por 09.05.2018 / 12:14
0

Usando perl - assumindo apenas # na entrada como dado na amostra

$ perl -pe 's/[^#]\K#.*|^#//' ip.txt
abc
nrt
clb1aX
amd
  • [^#]\K#.* para excluir todos os caracteres da primeira ocorrência de # se houver um caractere não # anterior a
  • |^# caso contrário, remova # do início da linha


Mesma coisa com sed

$ sed 's/\([^#]\)#.*\|^#//' ip.txt
abc
nrt
clb1aX
amd
    
por 09.05.2018 / 13:05
0

Outro sed

sed 's/^#*\([^#]*\).*//' infile

Se você deseja remover linhas apenas com ####

sed 's/^#*\([^#]*\).*//;/^$/d' infile
    
por 09.05.2018 / 17:00
0
awk '{sub(/^#/,"")sub(/#/," &");print $1}' file

abc
nrt
clb1aX
amd
    
por 11.05.2018 / 01:28