Como substituir um char para obter muitas strings no Shell?

5

Eu posso encontrar muitas perguntas com respostas na outra direção, mas infelizmente não na que eu gostaria de ter minhas substituições: Eu pretendo substituir um char , como # , < strong> em uma string , como test#asdf , com uma sequência, como {0..10} para obter uma seqüência de strings , neste exemplo test0asdf test1asdf test2asdf test3asdf test4asdf test5asdf test6asdf test7asdf test8asdf test9asdf test10asdf .

Eu tentei de outras pessoas:

  • echo '_#.test' | tr # {0..10} (lança uso)
  • echo '_#.test' | sed -r 's/#/{0..10}/g' (retorna _{0..10}.test )
  • echo '_#.test' | sed -r 's/#/'{0..10}'/g' (funciona para o primeiro, depois eu recebo sed: can't read (...) no such file or directory )

O que é uma abordagem de trabalho para esse problema?

Editar, como posso não comentar ainda: Eu tenho que usar # na string, na qual esse caractere deve ser substituído, como a string passada de outro programa. Eu poderia primeiro substituí-lo com outro char embora.

    
por BernhardWebstudio 27.08.2018 / 20:18

6 respostas

6

O operador {0..10} zsh (agora também suportado por alguns outros shells incluindo bash ) é apenas uma outra forma de expansão de chave de estilo csh .

É expandido pelo shell antes de chamar o comando. O comando não vê esses {0..10} .

Com tr '#' {0..10} (citando que # , caso contrário, é analisado pelo shell como o início de um comentário), tr termina sendo chamado com ("tr", "#", "0", "1 ", ...," 10 ") como argumentos e tr não espera muitos argumentos.

Aqui, você deseja:

echo '_'{0..10}'.test' 

para echo ser passado como "_0.test", "_1.test", ..., "_10.test" como argumentos.

Ou se você quiser que # seja traduzido nesse operador {0..10} , transforme-o em código de shell a ser avaliado:

eval "$(echo 'echo _#.test' | sed 's/#/{0..10}/')"

onde eval está sendo passado echo _{0..10}.test como argumentos.

(não que eu recomendaria fazer algo assim).

    
por 27.08.2018 / 20:32
5

Você pode dividir a string no delimitador, capturar o prefixo e o sufixo e usar a expansão da chave para gerar os nomes:

str='test#asdf'
IFS='#' read -r prefix suffix <<<"$str"
names=( "$prefix"{0..10}"$suffix" )
declare -p names
declare -a names='([0]="test0asdf" [1]="test1asdf" [2]="test2asdf" [3]="test3asdf" [4]="test4asdf" [5]="test5asdf" [6]="test6asdf" [7]="test7asdf" [8]="test8asdf" [9]="test9asdf" [10]="test10asdf")'
    
por 27.08.2018 / 21:07
2

Você precisa usar # ? Talvez você possa usar %d ?

$ for i in {1..10}; do printf "_%d.test " "$i"; done
_1.test _2.test _3.test _4.test _5.test _6.test _7.test _8.test _9.test _10.test
    
por 27.08.2018 / 20:29
2

Primeiro # inicia um comentário. Então, você precisa escapar com \ .

Em segundo lugar, use um loop for .

Aqui está sua solução:

for i in {1..10}
do
    echo '_#.test' | tr \# $i
done

tr infelizmente não funciona para mais de um caractere, por exemplo, quando você deseja substituir # por 10 . Você está melhor usando sed por esse motivo.

for i in {1..10}
do
    echo '_#.test' | sed "s/#/$i/"
done
    
por 27.08.2018 / 20:26
1

Eu faria isso com a expansão de parâmetros :

$ var='test#asdf'
$ for i in {1..10}; do echo "${var/\#/"$i"}"; done
test1asdf
test2asdf
test3asdf
test4asdf
test5asdf
test6asdf
test7asdf
test8asdf
test9asdf
test10asdf

A expansão ${parameter/pattern/string}

  • leva a expansão de $parameter (no nosso caso, $var ) e
  • substitui a primeira ocorrência de pattern (o escape # - /# tem um significado especial no contexto, "substituir no início da string", que queremos evite) com
  • string ( "$i" no nosso caso)

Como alternativa, você pode substituir o # por %d e usá-lo como a string de formato para printf :

printf "${var/\#/%d}\n" {1..10}
    
por 27.08.2018 / 20:52
0

Se o que você precisa é de uma expansão de string, então isso é suficiente:

echo 'test'{1..11}'asdf'
test1asdf test2asdf test3asdf test4asdf test5asdf test6asdf test7asdf test8asdf test9asdf test10asdf test11asdf

Se você precisar substituir um # em várias strings, use os argumentos posicionais:

$ set -- test#asdf{,,,,,,,,,,}
$ printf '%s ' "$@"; echo
test#asdf test#asdf test#asdf test#asdf test#asdf test#asdf test#asdf test#asdf test#asdf

$ j=0; for i do echo "${i//#/"$((j+=1))"}"; done
test1asdf
test2asdf
test3asdf
test4asdf
test5asdf
test6asdf
test7asdf
test8asdf
test9asdf
test10asdf
test11asdf
    
por 28.08.2018 / 00:58