problema de expansão de teste de variável de shell

2

Eu tenho este código:

sed \
$( (( $compress == 1 )) && echo -n '-e /^RMTHOST/ s/$/, compress/' ) \
-e "s|\*\*jobname\*\*|$jobname|g" \
-e "s|\*\*hostname\*\*|$hostname|g" \
-e "s|\*\*hostport\*\*|$hostport|g" \
-e "s|\*\*rmttrailname\*\*|$rmttrailname|g" < $GGPARAMSDIR/pump.template > 
$GGPARAMSDIR/$jobname.prm

que quase funciona como eu quero. Se $compress == 1 , eu quero que o sed inclua a string -e /^RMTHOST/ s/$/, compress/' . E se $compress != 1 , não inclua essa seção.

Estou recebendo o seguinte erro quando $compress is 1

 sed: -e expression #1, char 10: missing command

Quando adiciono um conjunto -x ao script para depuração, ele se expande para o seguinte:

sed -e '/^RMTHOST/' 's/$/,' compress/ -e 's|\*\*jobname\*\*|pssic|g' -e 's|\*\*hostname\*\*|omsssi|g' -e 's|\*\*hostport\*\*|7809|g' -e 's|\*\*rmttrailname\*\*|./dirdat/dsn/rc|g'

Repare que o único sinal fecha a primeira expressão -e após o /^RMTHOST/ , o que, tenho certeza, é a causa do meu problema. Mas não consigo descobrir a sintaxe para corrigi-lo.

FYI, os valores das variáveis são jobname=pssic , hostname=omsssi e hostport=7809

Alguém pode ajudar?

    
por bfoddy 21.12.2017 / 02:15

2 respostas

4

O problema

O problema é que o resultado de uma substituição de comando é submetido à expansão do nome do caminho e à divisão de palavras.

Para ver o que acontece com a saída da substituição do comando, vamos usar printf para exibir as palavras que ele produz:

$ printf ">%s<\n" $( (( compress == 1 )) && echo -n '-e /^RMTHOST/ s/$/, compress/' )
>-e<
>/^RMTHOST/<
>s/$/,<
>compress/<

Você precisa que -e seja uma palavra separada. Observe, no entanto, que a divisão de palavras também fez com que o comando substituto do sed fosse dividido em algo que o sed não entenderá :

$ sed -e '/^RMTHOST/' 's/$/,' 'compress/'
sed: -e expression #1, char 10: missing command

A solução

Tente usar matrizes do bash em vez disso:

#!/bin/bash
jobname=pssic
hostname=omsssi
hostport=7809
compress=1
rmttrailname=SomethingElse

args=()
(( compress == 1 )) && args+=('-e' '/^RMTHOST/ s/$/, compress/')
args+=(
    -e "s|\*\*jobname\*\*|$jobname|g"
    -e "s|\*\*hostname\*\*|$hostname|g"
    -e "s|\*\*hostport\*\*|$hostport|g"
    -e "s|\*\*rmttrailname\*\*|$rmttrailname|g"
    )

declare -p args  # Optional: Verify the args are what we want.

sed "${args[@]}" <"$GGPARAMSDIR/pump.template" >"$GGPARAMSDIR/$jobname.prm"

Boa leitura

Uma discussão interessante e mais geral sobre os problemas de criação de comandos a partir de variáveis shell é: "Estou tentando colocar um comando em uma variável, mas os casos complexos sempre falham! "

    
por 21.12.2017 / 02:39
0

Uma solução POSIX:

As substituições de comandos

sem aspas estão sujeitas à divisão de palavras.

Alterar:

$( (( $compress == 1 )) && echo -n '-e /^RMTHOST/ s/$/, compress/' ) \

Para (citar a expansão):

-e "$( [ "$compress" -eq 1 ] && printf '%s' '/^RMTHOST/ s/$/, compress/' )" \

Isso define dois argumentos, um é -e e o outro é o string sed necessário.

Roteiro editado:

#!/bin/sh

compress=$1
jobname=pssic
hostname=omsssi
hostport=7809
rmttrailname=ends
#set -x
echo "RMTHOST **jobname** **hostname** **hostport** **rmttrailname** test" | \
    sed \
    -e "$( [ "$compress" -eq 1 ] && printf '%s' '/^RMTHOST/ s/$/, compress/' )" \
    -e "s|\*\*jobname\*\*|$jobname|g" \
    -e "s|\*\*hostname\*\*|$hostname|g" \
    -e "s|\*\*hostport\*\*|$hostport|g" \
    -e "s|\*\*rmttrailname\*\*|$rmttrailname|g"
#set +x

E testando o código (sem set -x ):

$  ./so 1
RMTHOST pssic omsssi 7809 ends test, compress

Se o conjunto -x não tiver comentário:

$ ./so 1
+ echo RMTHOST **jobname** **hostname** **hostport** **rmttrailname** test
+ [ 1 -eq 1 ]
+ printf %s /^RMTHOST/ s/$/, compress/
+ sed -e /^RMTHOST/ s/$/, compress/ -e s|\*\*jobname\*\*|pssic|g -e s|\*\*hostname\*\*|omsssi|g -e s|\*\*hostport\*\*|7809|g -e s|\*\*rmttrailname\*\*|ends|g
RMTHOST pssic omsssi 7809 ends test, compress
+ set +x

Shells que usam matrizes

Uma abordagem completamente diferente (e a melhor prática) é acumular todos os argumentos como uma matriz (somente shells que possuem matrizes):

#!/bin/bash
compress=$1
jobname=pssic
hostname=omsssi
hostport=7809
rmttrailname=ends

args=()
(( compress == 1 )) && args+=('-e' '/^RMTHOST/ s/$/, compress/')
args+=( -e "s|\*\*jobname\*\*|$jobname|g" )
args+=( -e "s|\*\*hostname\*\*|$hostname|g" )
args+=( -e "s|\*\*hostport\*\*|$hostport|g" )
args+=( -e "s|\*\*rmttrailname\*\*|$rmttrailname|g" )

echo "RMTHOST **jobname** **hostname** **hostport** **rmttrailname** test" | \
    sed "${args[@]}"

Em exibição:

$ ./script 1
RMTHOST pssic omsssi 7809 ends test, compress
    
por 21.12.2017 / 03:26