Com base na resposta do devnull, eu juntei isto:
echo $LINE | tr '+' '\n' | grep "prop1=$VALUE" | tr ':' '\n' | grep "prop2=" | cut -d= -f2
Ainda estou aberto a respostas melhores.
Estou analisando dados no seguinte formato:
prop1=value1:prop2=value2:prop3=value3+prop1=value4:prop2=value5
+
Posso conseguir isso por meio de ferramentas de linha de comando padrão do UNIX, ou preciso escrever um pequeno programa em C?
Editar - para a linha mostrada, esta é a funcionalidade desejada:
input: value1 -> output: value2
input: value4 -> output: value5
Você pode usar gawk
:
awk -F'+' '{for(i=1;i<=NF;i++){if($i ~ /value1/)
{$i=gensub(/.*prop2=(.*)(:.*|.*$)/,"\1","g",$i);print $i}}}' file
Se você não se importa com o Perl:
perl -053nE '
BEGIN{ $value = shift }
chomp;
tr {=:}{ };
%h = eval "qw($_)";
say $h{prop2} if $h{prop1} eq $value
' your_file value1
Isso não assume nenhuma ordem particular de propriedades, mas supõe que nem os nomes nem os valores das propriedades conterão espaços. Se isso não for verdade, será necessária mais análise.
Explicação
-053
define o separador de registro para o caractere ASCII cujo código octal é 53
, ou seja, +
. -n
significa aplicar o trabalho em um registro por vez, alterando $_
para o conteúdo do registro. -E
significa executar o seguinte código com as opções anteriores em mente.
O código com comentários:
perl -053nE '
BEGIN{ $value = shift } # $value now = the command line argument
chomp; # Remove the record separator (+)
tr {=:}{ }; # Make all '=' and ':' into a space
%h = eval "qw($_)"; # Parse the line into a hash (explained below)
say $h{prop2} if $h{prop1} eq $value # This is your required logic
' your_file value1
O operador qw()
usa uma lista separada por espaços e cita corretamente suas palavras constituintes para criar uma lista. Quando aplicado ao registro
prop1 value1 prop3 value3 prop2 value2
(lembre-se de como alteramos todos os +
e =
em um espaço), ele transforma o registro em uma lista. Quando esta lista é atribuída a uma variável hash %h
, assume-se que as chaves hash são os elementos ímpares da lista e os valores hash são os pares mesmo.
Supondo que você sempre desejará o primeiro prop1
depois , qualquer que seja o value
que você passar, poderá fazer:
$ perl -lne '/prop1=value1[:+].*?prop2=([^:+]+)/ && print $1' file
value2
$ perl -lne '/prop1=value4[:+].*?prop2=([^:+]+)/ && print $1' file
value5
A ideia aqui é corresponder a prop1=valueN
. O value4[:+]
certifica-se de que todo o valor está marcado, até o próximo delimitador de campo ( :
ou +
), de modo que value4
não corresponda a value44
, por exemplo. Em seguida, 0 ou mais caracteres ( .*?
), seguidos por prop2=
e o valor de prop2
.
Você pode tentar algo como:
awk '{
for(i = 1; i <= NF; i++) {
split($i, tmp, /=/)
if(tmp[1] == "prop1") {
printf " %s%s", "input: ",tmp[2]
}
if(tmp[1] == "prop2") {
printf " %s%s", "output: ",tmp[2]
}
}
print ""
}' RS='+' FS=':' file
Saída (com sua entrada de amostra):
input: value1 output: value2
input: value4 output: value5
awk -F"[:=]" -vRS='+' '{for(i=1; i<=NF; i++) {if($i == "prop1") I=$(i+1); if($i == "prop2") O=$(i+1)}; printf "input: %s -> output: %s\n", I, O}' file
awk -vRS='+|\n' '
BEGIN{ p1=":prop1="; p2=":prop2=" }
{ if( ":"$0":" ~ p1 p1val ":" ) {
if( match(":"$0":", p2 "[^:]+:" ) ) {
print substr($0, RSTART+length(p2)-1, RLENGTH-length(p2)-1)
}}}' p1val=value4
Canalize sua string (ou arquivo) em awk
.
O valor de prop1 é inserido por meio de uma variável-arg p1val=
como mostrado.
Saída para entrada: p1val=value1
value2
Saída para entrada: p1val=value4
value5
Tags command-line awk sed