Como repetir alguns personagens algumas vezes em Bash?
-
26-09-2019 - |
Pergunta
Em um script bash, tenho que incluir o mesmo arquivo várias vezes seguidas como argumento. Assim:
convert image.png image.png image.png [...] many_images.png
Onde image.png
deve ser repetido algumas vezes.
Existe uma abreviação de rebaixamento para repetir um padrão?
Solução
Isso funciona com um determinado número inteiro (10 no exemplo abaixo).
$ echo $(yes image.png | head -n10)
image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png
Também pode ser usado com xargs
:
$ yes image.png | head -n10 | xargs echo
image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png
Outras dicas
Você pode fazer isso usando a expansão do BRACE:
convert image.png{,,} many_images.png
vai produzir:
convert image.png image.png image.png many_images.png
A expansão do BRACE repetirá a (s) sequência (s) antes (e depois) o aparelho para cada string separada por vírgula dentro dos aparelhos que produzem uma string que constê o prefixo, a sequência separada por vírgula e o sufixo; e separando as cordas geradas por um espaço.
Nesse caso, a corda separada por vírgula entre os aparelhos e o sufixo são seqüências vazias que produzirão a imagem da corda. PNG três vezes.
#!/bin/bash
function repeat {
for ((i=0;i<$2;++i)); do echo -n $1 " "; done
}
convert $(repeat image.png 3) many_images.png
Aqui está uma solução que usa matrizes e, portanto, é robusta para cordas que contêm espaços, linhas news etc.
declare -a images
declare -i count=5
for ((i=0; i<count; ++i))
do
images+=(image.png)
done
convert "${images[@]}" many_images.png
Isso pode funcionar para você:
convert $(printf "image.png %.s" {1..5}) many_images.png
Isso vai repetir image.png
5 vezes antes many_images.png
Para evitar o código lento que abre instâncias desnecessárias de bash usando $ (comando) ou command
Você pode usar a expansão do aparelho.
Para repetir um nome de arquivo 3 vezes o faça:
file="image.png"; convert "${file[0]"{1..3}"}" many_images.png
ou uma versão mais controversa que usa uma variável para especificar o número de nomes de arquivos repetidos:
n=10; file="image.png"; eval convert \"\${file[0]\"{1..$n}\"}\" many_images.png
Como funciona.
$ {arquivo [0]} é o mesmo que $ arquivo ou $ {arquivo}
O Bash abre primeiro a expansão e, portanto, compõe uma sequência como esta:
${file[0]1} ${file[0]2} ${file[0]3}
Bash gentilmente ignore esses números extras para obter
${file[0]} ${file[0]} ${file[0]}
O que simplifica
${file} ${file} ${file}
e depois
$file $file $file
Que é o que queremos.
Mais curto Posix 7 Solução que encontrei até agora:
N=3
S="image.png "
printf "%${N}s" | sed "s/ /$S/g"
desde yes
, seq
e {1..3}
não são posix.
Para o seu exemplo específico:
N=
convert $(printf "%${N}s" | sed "s/ /image.png /g") many_images.png