Problema ao passar uma variável para sed

4

Eu sei que ao passar uma variável para sed, deve-se usar aspas duplas. Então, quando eu estava usando sed para exibir uma linha de um arquivo dado um número de linha:

sed '894!d' cloud.cpp

Funciona, mas desde que eu também quero passar o número de linha 894 para sed como uma variável, então eu tentei:

lnum=894
sed "$lnum!d" cloud.cpp

Mas isso não funciona, e até mesmo aspas simples com a mesma sintaxe não funcionam:

sed "894!d" cloud.cpp

Então, neste caso, como eu ainda posso passar uma variável para sed?

    
por phonycollectibles 14.12.2016 / 08:33

3 respostas

5

Como você mencionou, você deve usar aspas duplas, porque quando você usa aspas simples para seqüências de caracteres, seu conteúdo será tratado literalmente. Mas no seu caso, você tem uma combinação de padrão e variável. Portanto, você deve usar aspas simples para o padrão e aspas duplas para a variável:

sed "$lnum"'!d' cloud.cpp
    
por 14.12.2016 / 08:54
8

Se a sua variável contiver apenas um dígito, o que você fez está correto:

sed "$lnum!d" cloud.cpp

Para passar a variável shell para sed em geral, leia esta resposta .

Agora, você fez isso corretamente neste caso, mas ainda não funciona. Isso é devido ao seu shell, que provavelmente bash , zsh ou csh . Esses shells suportam a expansão do histórico, que é denotada por ! (esse recurso é original de csh e copiado posteriormente por bash e zsh ).

Em bash , zsh , a expansão de histórico é ativada por padrão na sessão interativa e será executada entre aspas duplas.

Em zsh :

$ seq 10 | sed "10!d" # <-- press enter
$ seq 10 | sed "10dash"

como dash é meu último comando no histórico, comece com d .

Em bash :

$ seq 10 | sed "10!d"
bash: !d": event not found

como eu não tenho nenhum comando no bash history comece com d .

Você pode desativar a expansão do histórico:

set +H

ou:

set +o histexpand

em bash e:

set -K

ou:

setopt nohistexpand

em zsh .

Para uma forma mais portátil, sem confiar nas suas opções de shell, você sempre pode fazer:

sed "$lnum"\!d cloud.cpp

que faz com que seu shell trate ! literalmente.

    
por 14.12.2016 / 09:04
4

Você não mencionou qual shell está usando. A resposta abaixo assume que é bash .

Você está acionando a expansão do histórico no shell. De man bash :

!string

Refer to the most recent command preceding the current position in the history list starting with string.

O mais estranho é que:

If enabled, history expansion will be performed unless an ! appearing in double quotes is escaped using a backslash. The backslash preceding the ! is not removed.

Portanto, acho que citá-las separadamente é provavelmente a melhor solução:

sed "$lnum"'!d' cloud.cpp

Isso também funciona (economizando um char):

sed "$lnum"\!d cloud.cpp

Isso também funciona (se você favorecer aspas duplas):

sed "$lnum""!""d" cloud.cpp
    
por 14.12.2016 / 09:13