Dicas para jogar golfe em Bash


55

Que dicas gerais você tem para jogar golfe no Bash? Estou procurando idéias que possam ser aplicadas para codificar problemas de golfe em geral que sejam pelo menos um pouco específicos para o Bash (por exemplo, "remover comentários" não é uma resposta). Poste uma dica por resposta.

Respostas:


36

Não documentado , mas funciona em todas as versões que encontreishpara compatibilidade com versões anterioresherdadas:

forloops permitem que você use em { }vez de do done. Por exemplo, substituir:

for i in {1..10};do echo $i; done

com:

for i in {1..10};{ echo $i;}

qual shell é she qual shell permite essa forsintaxe? é expressamente permitido entrar zsh.
mikeserv

@mikeserv Bash. Lembro-me de ler em algum lugar que essa sintaxe era permitida em alguns shtempos antigos e que o Bash também o permite por causa disso, embora, infelizmente, não tenha uma citação.
Digital Trauma

ahh ... csh, provavelmente - foi assim que eles trabalharam nessa concha.
mikeserv

a propósito, na ksh93coisa acima poderia ser ;{1..10}bashprintf %s\\n {1..10}
:,

11
for((;i++<10)){ echo $i;}é mais curto quefor i in {1..10};{ echo $i;}
Evan Krall

29

Para expansão aritmética, use em $[…]vez de $((…)):

bash-4.1$ echo $((1+2*3))
7

bash-4.1$ echo $[1+2*3]
7

Em expansões aritméticas, não use $:

bash-4.1$ a=1 b=2 c=3

bash-4.1$ echo $[$a+$b*$c]
7

bash-4.1$ echo $[a+b*c]
7

A expansão aritmética é realizada em subscritos de matriz indexada, portanto, não use $nem lá:

bash-4.1$ a=(1 2 3) b=2 c=3

bash-4.1$ echo ${a[$c-$b]}
2

bash-4.1$ echo ${a[c-b]}
2

Em expansões aritméticas, não use ${…}:

bash-4.1$ a=(1 2 3)

bash-4.1$ echo $[${a[0]}+${a[1]}*${a[2]}]
7

bash-4.1$ echo $[a[0]+a[1]*a[2]]
7

Substituição while((i--)), que funciona, com while[i--]ou while $[i--]não funcionou para mim. GNU bash, versão 4.3.46 (1)
Glenn Randers-Pehrson /

11
Correto, @ GlennRanders-Pehrson. Isso não deveria funcionar.
Manatwork

y=`bc<<<"($x*2.2)%10/1"`... exemplo de uso bcpara cálculos não inteiros ... observe que /1no final trunca o decimal resultante para um int.
roblogic 23/03

s=$((i%2>0?s+x:s+y))... exemplo de uso do operador ternário na aritmética do bash. É mais curto que if..then..elseou[ ] && ||
roblogic 23/03

11
@manatwork Obrigado. Eles devem ter removido. Estou ligado GNU bash, version 5.0.2(1)-release (x86_64-apple-darwin16.7.0)e não está no meu.
Jonah

19

A maneira normal, longa e chata de definir uma função é

f(){ CODE;}

Como esse cara descobriu, você precisa absolutamente do espaço antes CODEe do ponto e vírgula depois dele.

Este é um pequeno truque que aprendi no @DigitalTrauma :

f()(CODE)

São dois caracteres mais curtos e funciona da mesma forma, desde que você não precise transportar nenhuma alteração nos valores das variáveis ​​após o retorno da função ( os parênteses executam o corpo em uma subshell ).

Como @ jimmy23013 aponta nos comentários, até os parênteses podem ser desnecessários.

O Manual de Referência do Bash mostra que as funções podem ser definidas da seguinte maneira:

name () compound-command [ redirections ]

ou

function name [()] compound-command [ redirections ]

Um comando composto pode ser:

  • a construção de loop: until, whileoufor
  • uma Construção Condicional: if, case, ((...))ou[[...]]
  • Comandos agrupados: (...)ou{...}

Isso significa que todos os itens a seguir são válidos:

$ f()if $1;then $2;fi
$ f()($1&&$2)
$ f()(($1))                # This one lets you assign integer values

E eu tenho usado colchetes como um otário ...


2
Observe que você também pode usar f()while ... f()if ...e outros comandos compostos.
precisa saber é o seguinte

Este me surpreendeu porque eu pensei que f()CODEera legal. Acontece que isso f()echo hié legal no pdksh e no zsh, mas não no bash.
kernigh

11
é especialmente útil com foro padrão de posicionais: f()for x do : $x; done;set -x *;PS4=$* f "$@"ou algo assim.
mikeserv

16

:é um comando que não faz nada, seu status de saída sempre é bem-sucedido e, portanto, pode ser usado em vez de true.


Usando um subshell e canal, ele usaria o mesmo número de bytes, mas o canal seria mais prático.
Ckjbgames

5
Exceto quando você faz:(){:|:}
enedil

14

Mais dicas

  1. Abuse o operador ternário ((test)) && cmd1 || cmd2ou [ test ] && cmd1 || cmd2, tanto quanto possível.

    Exemplos (contagens de comprimento sempre excluem a linha superior):

    t="$something"
    if [ $t == "hi" ];then
    cmd1
    cmd2
    elif [ $t == "bye" ];then
    cmd3
    cmd4
    else
    cmd5
    if [ $t == "sup" ];then
    cmd6
    fi
    fi
    

    Usando apenas operadores ternários, isso pode ser facilmente reduzido para:

    t="$something"
    [ $t == "hi" ]&&{
    cmd1;cmd2
    }||[ $t == "bye" ]&&{
    cmd3;cmd4
    }||{
    cmd5
    [ $t == "sup" ]&&cmd6
    }
    

    Como nyuszika7h apontou nos comentários, este exemplo específico pode ser reduzido ainda mais usando case:

    t="$something"
    case $t in "hi")cmd1;cmd2;;"bye")cmd3;cmd4;;*)cmd5;[ $t == "sup" ]&&cmd6;esac
    
  2. Além disso, prefira parênteses a chaves, tanto quanto possível. Como os parênteses são um metacaractere, e não uma palavra, eles nunca requerem espaços em nenhum contexto. Isso também significa executar o maior número possível de comandos em um subshell, porque chaves entre chaves (ie {e }) são palavras reservadas, não meta caracteres, e, portanto, precisam ter espaço em branco em ambos os lados para analisar corretamente, mas as meta caracteres não. Suponho que você já saiba que os subshells não afetam o ambiente pai; portanto, supondo que todos os comandos de exemplo possam ser executados com segurança em um subshell (o que não é típico em nenhum caso), você pode encurtar o código acima para isso :

    t=$something
    [ $t == "hi" ]&&(cmd1;cmd2)||[ $t == "bye" ]&&(cmd3;cmd4)||(cmd5;[ $t == "sup" ]&&cmd6)
    

    Além disso, se você não puder, usar parênteses ainda poderá reduzi-lo um pouco. Um aspecto a ter em mente é que ele funciona apenas para números inteiros, o que o torna inútil para os fins deste exemplo (mas é muito melhor do que usar -eqpara números inteiros).

  3. Mais uma coisa, evite aspas sempre que possível. Usando o conselho acima, você pode reduzi-lo ainda mais. Exemplo:

    t=$something
    [ $t == hi ]&&(cmd1;cmd2)||[ $t == bye ]&&(cmd3;cmd4)||(cmd5;[ $t == sup ]&&cmd6)
    
  4. Nas condições de teste, prefira colchetes simples a duplos, tanto quanto possível, com algumas exceções. Ele solta dois caracteres de graça, mas em alguns casos não é tão robusto (é uma extensão do Bash - veja abaixo um exemplo). Além disso, use o argumento igual a um e não o dobro. É um personagem grátis para soltar.

    [[ $f == b ]]&&: # ... <-- Bad
    [ $f == b ]&&: # ... <-- Better
    [ $f = b ]&&: # ... <-- Best.  word splits and pathname-expands the contents of $f.  Esp. bad if it starts with -
    

    Observe esta ressalva, especialmente na verificação de saída nula ou de uma variável indefinida:

    [[ $f ]]&&:    # double quotes aren't needed inside [[, which can save chars
    [ "$f" = '' ]&&: <-- This is significantly longer
    [ -n "$f" ]&&:
    

    Com toda a tecnicidade, este exemplo específico seria melhor com case... in:

    t=$something
    case $t in hi)cmd1;cmd2;;bye)cmd3;cmd4;;*)cmd5;[ $t == sup ]&&cmd6;esac
    

Então, a moral deste post é a seguinte:

  1. Abuse os operadores booleanos o máximo possível e sempre os use em vez de if/ if-else/ etc. construções.
  2. Use parênteses o máximo possível e execute o maior número possível de segmentos em subshells porque os parênteses são metacaracteres e não palavras reservadas.
  3. Evite citações, tanto quanto fisicamente possível.
  4. Confira case... in, pois ele pode economizar alguns bytes, principalmente na correspondência de cadeias.

PS: Aqui está uma lista de meta-caracteres reconhecidos no Bash, independentemente do contexto (e podem separar palavras):

&lt; &gt; ( ) ; & | &lt;space&gt; &lt;tab&gt;

EDIT: Como apontou manatwork, o teste de parênteses duplos funciona apenas para números inteiros. Além disso, indiretamente, descobri que você precisa ter um espaço em branco ao redor do ==operador. Corrigido minha postagem acima.

Eu também estava com preguiça de recalcular o comprimento de cada segmento, então simplesmente os removi. Deve ser fácil encontrar uma calculadora de comprimento de cordas online, se necessário.


Lamento dizer, mas você tem alguns erros sérios lá. [ $t=="hi" ]sempre avaliará como 0, pois é analisado como [ -n "STRING" ]. (($t=="hi"))sempre avaliará como 0, desde que $ t tenha valor não numérico, pois as strings são forçadas a números inteiros nas avaliações aritméticas. Alguns casos de teste: pastebin.com/WefDzWbL
manatwork

@manatwork Obrigado pela captura. Vou atualizar em conformidade.
Isiah Meadows

Usar um caseseria mais curto aqui. Além disso, você não precisa de um espaço antes }, mas precisa depois {.
nyuszika7h

11
Por que =seria menos robusto do que ==? =é mandatado pelo POSIX, ==não é.
Dennis

11
A questão é que pedir uma dica por resposta ...
Toby Speight

7

Em vez de grep -E, grep -F, grep -r, uso egrep, fgrep, rgrep, salvando dois caracteres. Os mais curtos estão obsoletos, mas funcionam bem.

(Você pediu uma dica por resposta!)


11
Pena que não há Pgreppara grep -P. Embora eu veja como isso pode ser facilmente confundido pgrep, o qual é usado para procurar processos.
precisa saber é o seguinte

11
@ nyuszika7h Eu pessoalmente uso grep -omuito

Não economizaria 3, incluindo o espaço?
Ckjbgames

7

O elemento 0 de uma matriz pode ser acessado apenas com o nome da variável, economizando cinco bytes e especificando explicitamente um índice 0:

$ a=(code golf)
$ echo ${a[0]}
code
$ echo $a
code
$ 

7

Se você precisar passar o conteúdo de uma variável para STDIN do próximo processo em um pipeline, é comum ecoar a variável em um pipeline. Mas você pode conseguir o mesmo com uma <<< string bash here :

$ s="code golf"
$ echo "$s"|cut -b4-6
e g
$ cut -b4-6<<<"$s"
e g
$ 

2
Desde que nós estamos golfe, s=code\ golf, echo $s|e <<<$s(tendo em mente que os dois últimos trabalhos só porque existem espaços não repetidas, etc.).
Dennis

6

Evite $( ...command... ), existe uma alternativa que salva um caractere e faz a mesma coisa:

` ...command... `

9
Às vezes $( )é necessário se você tiver aninhado substituições de comando; caso contrário, você teria que escapar do interior``
Digital Trauma

11
Tecnicamente, isso faz coisas diferentes. Eu tive que usar os backticks em vez de $()quando eu queria executar a substituição na minha máquina em vez da máquina de scpdestino, por exemplo. Na maioria dos casos, são idênticos.
Undergroundmonorail

2
@undergroundmonorail: você nunca precisa de backticks. Tudo o que eles podem fazer, $()pode fazer se você citar as coisas corretamente. (a menos que você precise do seu comando para sobreviver a algo que munges, $mas não backticks). Existem algumas diferenças sutis em citar coisas dentro deles. mywiki.wooledge.org/BashFAQ/082 explica algumas diferenças. A menos que você esteja jogando golfe, nunca use backticks.
Peter Cordes

@ PeterCordes Tenho certeza de que havia uma maneira, mas tudo o que tentei na época não funcionou. Mesmo que os backticks não fossem a melhor solução, fiquei feliz por conhecê-los porque era a única solução que eu tinha. ¯ \ _ (ツ) _ / ¯
undergroundmonorail

@DigitalTrauma Amostra de nidificação: echo `bc <<<"\`date +%s\`-12"`... (É difícil amostra pós contendo backtick no comentário, não;!)
F. Hauri

6

Use ifpara agrupar comandos

Comparado a essa dica que remove iftudo, isso só deve funcionar melhor em alguns casos muito raros, como quando você precisa dos valores de retorno de if.

Se você possui um grupo de comandos que termina com a if, como estes:

a&&{ b;if c;then d;else e;fi;}
a&&(b;if c;then d;else e;fi)

Você pode agrupar os comandos antes ifna condição:

a&&if b;c;then d;else e;fi

Ou se sua função terminar com um if:

f(){ a;if b;then c;else d;fi;}

Você pode remover os aparelhos:

f()if a;b;then c;else d;fi

11
Você pode usar o operador ternário [test] && $if_true || $elsenessas funções e salvar alguns bytes.
Ckjbgames

Além disso, você não precisa de espaços ao redor &&e||
roblogic 23/03

6

Use aritmética (( ... ))para condições

Você pode substituir:

if [ $i -gt 5 ] ; then
    echo Do something with i greater than 5
fi

por

if((i>5));then
    echo Do something with i greater than 5
fi

(Nota: não há espaço depois if)

ou mesmo

((i>5))&&{
    echo Do something with i greater than 5
}

... ou se apenas um comando

((i>5))&&echo Echo or do something with i greater than 5

Além disso: oculte a configuração variável na construção aritmética:

((i>5?c=1:0))&&echo Nothing relevant there...
# ...
((c))&&echo Doing something else if i was greater than 5

ou mesmo

((c=i>5?c=0,1:0))&&echo Nothing relevant there...
# ...
((c))&&echo Doing something else if i was greater than 5

... onde i> 5, então c = 1 (não 0;)


Você pode salvar 2 bytes usando em [ ]vez de (()).
Ckjbgames

@ckjbgames Você tem certeza disso !? Qual versão do bash você está usando?
F. Hauri 24/01

@FHauri Acho que seria o mesmo em termos de bytes.
precisa saber é o seguinte

@ckjbgames Com [ ]você precisa do cifrão para variável. Não vejo como você poderia fazer o mesmo com o mesmo ou menor comprimento usando [ ].
F. Hauri 24/01

Dica de bônus: se a primeira linha de um loop for começar ((...)), nenhuma nova linha ou espaço será necessário. Por exemplo, for((;10>n++;)){((n%3))&&echo $n;} experimente online!
Primo

6

Uma sintaxe mais curta para loops infinitos (que podem ser escapados com breakou exitinstruções) é

for((;;)){ code;}

Isso é mais curto que while true;e while :;.

Se você não precisar break(com exita única maneira de escapar), poderá usar uma função recursiva.

f(){ code;f;};f

Se você precisar interromper, mas não precisar sair e não precisar realizar nenhuma modificação de variável fora do loop, poderá usar uma função recursiva com parênteses ao redor do corpo , que executam o corpo da função em um subshell.

f()(code;f);f

6

forLoops de uma linha

Uma expressão aritmética concatenada com uma expansão de intervalo será avaliada para cada item no intervalo. Por exemplo, o seguinte:

: $[expression]{0..9}

avaliará expression10 vezes.

Isso geralmente é significativamente menor que o forloop equivalente :

for((;10>n++;expression with n)){ :;}
: $[expression with ++n]{0..9}

Se você não se importa com o comando não encontrou erros, pode remover o inicial :. Para iterações maiores que 10, você também pode usar intervalos de caracteres, por exemplo {A..z}, iterará 58 vezes.

Como exemplo prático, os seguintes itens produzem os primeiros 50 números triangulares, cada um em sua própria linha:

for((;50>d++;)){ echo $[n+=d];} # 31 bytes
printf %d\\n $[n+=++d]{A..r}    # 28 bytes

você também pode iterar para trás:for((;0<i--;)){ f;}
roblogic

5

Argumentos sobre loop

Como observado no Bash laço “for” sem “em foo bar ...” parte , o in "$@;"em for x in "$@;"é redundante.

De help for:

for: for NAME [in WORDS ... ] ; do COMMANDS; done
    Execute commands for each member in a list.

    The `for' loop executes a sequence of commands for each member in a
    list of items.  If `in WORDS ...;' is not present, then `in "$@"' is
    assumed.  For each element in WORDS, NAME is set to that element, and
    the COMMANDS are executed.

    Exit Status:
    Returns the status of the last command executed.

Por exemplo, se quisermos colocar todos os números ao quadrado, com argumentos posicionais para um script ou função do Bash, podemos fazer isso.

for n;{ echo $[n*n];}

Experimente online!


5

Alternativa para gato

Digamos que você esteja tentando ler um arquivo e usá-lo em outra coisa. O que você pode fazer é:

echo foo `cat bar`

Se o conteúdo de barfosse foobar, isso seria impresso foo foobar.

No entanto, existe uma alternativa se você estiver usando esse método, que economiza 3 bytes:

echo foo `<bar`

11
Existe uma razão <barpela qual, por si só, não funciona, mas colocá-lo em backticks funciona?
Kritixi Lithos

@Cowsquack Sim. Ele <coloca um arquivo em um comando, mas, neste caso, o coloca na saída padrão devido a uma peculiaridade. Os backticks avaliam isso juntos.
Okx 19/10/19

Existe uma maneira mais curta de ler a partir da entrada padrão diferente de `cat`?
Joel

4

Use em [vez de [[e testquando possível

Exemplo:

[ -n $x ]


Use em =vez de ==para comparação

Exemplo:

[ $x = y ]

Observe que você deve ter espaços ao redor do sinal de igual, caso contrário não funcionará. O mesmo se aplica a ==baseado nos meus testes.


3
A [vs [[pode depender da quantidade de citações necessários: pastebin.com/UPAGWbDQ
manatwork

@manatwork Esse é um bom ponto.
precisa saber é o seguinte

11
Regra geral: [... ]== /bin/test, mas [[... ]]! = /bin/testE nunca se deve preferir [... ]sobre [[... ]]fora do codegolf
cat

4

Alternativas para head

lineé três bytes menor que head -1, mas está sendo preterido .

sed qé dois bytes menor que head -1.

sed 9qé um byte menor que head -9.


11
Embora condenado , ainda podemos usar por um tempo linedo pacote util-linux para ler uma única linha.
precisa saber é o seguinte

4

tr -cd é mais curto que grep -o

Por exemplo, se você precisar contar espaços, grep -o <char>(imprima apenas o correspondente) fornece 10 bytes enquanto tr -cd <char>(excluir complemento de <char>) fornece 9.

# 16 bytes
grep -o \ |wc -l
# 15 bytes
tr -cd \ |wc -c

( fonte )

Observe que ambos fornecem resultados ligeiramente diferentes. grep -oretorna resultados separados por linha e tr -cdfornece todos na mesma linha; portanto, trnem sempre é favorável.


4

Encurtar nomes de arquivo

Em um desafio recente, eu estava tentando ler o arquivo /sys/class/power_supply/BAT1/capacity, no entanto, isso pode ser reduzido, /*/*/*/*/capac*ypois não existe outro arquivo com esse formato.

Por exemplo, se você tivesse um diretório foo/contendo os arquivos foo, bar, foobar, barfooe desejasse fazer referência ao arquivo foo/barfoo, poderá usar foo/barf*para salvar um byte.

O *representa "qualquer coisa" e é equivalente ao regex .*.


3

Use um pipe para o :comando em vez de /dev/null. O :built-in vai comer toda a sua entrada.


2
Não, ele travará o programa com o SIGPIPE na maioria dos casos. echo a|tee /dev/stderr|:não imprimirá nada.
precisa saber é o seguinte

Há uma corrida: echo a|tee /dev/stderr|:imprimi uma no meu computador, mas em outros lugares o SIGPIPE pode matar o tee primeiro. Pode depender da versão do tee.
kernigh

Sim, é um problema do SIGPIPE: tee >(:) < <(seq 1 10)funcionará, mas tee /dev/stderr | :não funcionará. Mesmo a() { :;};tee /dev/stderr < <(seq 1 10)| anão imprima nada.
F. Hauri 24/01

@ user16402 - você deve ter um nome fccing ao meu alcance ... de qualquer maneira, o :intrínseco não come nada ... se você supor entrada para dois pontos, poderá inundar um cano para erro de saída ... mas pode flutuar um redirecionamento por dois pontos, ou abandonar um processo com ele ... :| while i>&$(($??!$?:${#?})) command shit; do [ -s testitsoutput ]; doneou no entanto essa pseudo sugestão se aplica ... também, você sabe que é quase tão fantasmagórico quanto eu? ... evite a todo custo o< <(psycho shit i can alias to crazy math eat your world; okay? anyway, ksh93 has a separate but equal composite char placement)
mikeserv 10/09

3

splittem outra sintaxe (obsoleta, mas ninguém liga) para dividir a entrada em seções de Nlinhas cada: em vez de split -lNvocê pode usar, split -Npor exemplo split -9.


3

Expanda os testes

Essencialmente, o shell é um tipo de linguagem macro, ou pelo menos um híbrido ou algum tipo. Cada linha de comando pode ser basicamente dividida em duas partes: a parte de análise / entrada e a parte de expansão / saída.

A primeira parte é o foco da maioria das pessoas, porque é a mais simples: você vê o que recebe. A segunda parte é o que muitos evitam tentar entender muito bem, e é por isso que as pessoas dizem coisas evalruins e sempre citam suas expansões - as pessoas querem que o resultado da primeira parte seja igual ao primeiro. Tudo bem - mas isso leva a ramificações de código desnecessariamente longas e a toneladas de testes estranhos.

As expansões são autotestes . Os ${param[[:]#%+-=?]word}formulários são mais que suficientes para validar o conteúdo de um parâmetro, são aninhados e baseiam-se na avaliação do NUL - que é o que a maioria das pessoas espera dos testes de qualquer maneira. +pode ser especialmente útil em loops:

r()while IFS= read -r r&&"${r:+set}" -- "$@" "${r:=$*}";do :;done 2>&-

IFS=x
printf %s\\n some lines\ of input here '' some more|{ r;echo "$r"; }

somexlines ofxinputxhere

... enquanto readpuxa linhas não em branco se "${r:+set}"expande "set"e as posições são $ranexadas. Mas quando uma linha em branco é read, $restá vazia e se "${r:+set}"expande para ""- que é um comando inválido. Porém, como a linha de comando é expandida antes da ""pesquisa do comando nulo, "${r:=$*}"leva também os valores de todas as posições concatenadas no primeiro byte $IFS. r()poderia ser chamado novamente no |{comando composto ;}com um valor diferente para $IFSobter o próximo parágrafo de entrada também, pois é ilegal que um shell seja readarmazenado em buffer além da próxima linha de \new na entrada.


3

Use a recursão da cauda para diminuir os loops:

Eles são equivalentes em comportamento (embora provavelmente não estejam no uso de memória / PID):

while :;do body; done
f()(body;f);f
body;exec $0
body;$0

E estes são aproximadamente equivalentes:

while condition; do body; done
f()(body;condition&&f);f
body;condition&&exec $0
body;condition&&$0

(tecnicamente, os três últimos sempre executam o corpo pelo menos uma vez)

O uso $0requer que seu script esteja em um arquivo, não colado no prompt do bash.

Eventualmente, sua pilha pode estourar, mas você salva alguns bytes.


3

Às vezes, é mais curto usar o exprbuilt-in para exibir o resultado de uma expressão aritmética simples, em vez da usual echo $[ ]. Por exemplo:

expr $1 % 2

é um byte menor que:

echo $[$1%2]

2

Use em pwdvez de echopara gerar uma linha de saída

Precisa colocar uma linha no stdout, mas não se importa com o conteúdo e deseja restringir sua resposta aos shell builtins? pwdé um byte menor que echo.


2

As cotações podem ser omitidas ao imprimir seqüências de caracteres.

echo "example"
echo example

Saída no SM-T335 LTE, Android 5.1.1:

u0_a177@milletlte:/ $ echo "example"
example
u0_a177@milletlte:/ $ echo example
example

2

Ao atribuir itens de matriz não contínuos, você ainda pode pular os índices sucessivos de blocos contínuos:

bash-4.4$ a=([1]=1 [2]=2 [3]=3 [21]=1 [22]=2 [23]=3 [31]=1)

bash-4.4$ b=([1]=1 2 3 [21]=1 2 3 [31]=1)

O resultado é o mesmo:

bash-4.4$ declare -p a b
declare -a a=([1]="1" [2]="2" [3]="3" [21]="1" [22]="2" [23]="3" [31]="1")
declare -a b=([1]="1" [2]="2" [3]="3" [21]="1" [22]="2" [23]="3" [31]="1")

De acordo com man bash:

As matrizes são atribuídas ao uso de atribuições compostas do nome do formulário = (valor 1 ... valor n ), em que cada valor é do formato [ subscrito ] = sequência . As atribuições de matriz indexada não exigem nada além de sequência . Ao atribuir a matrizes indexadas, se os colchetes e subscritos opcionais forem fornecidos, esse índice será atribuído; caso contrário, o índice do elemento designado é o último índice atribuído pela instrução mais um.


Útil para adicionar: elementos não inicializados serão expandidos para 0 em expansões aritméticas e "" em outras expansões.
Digital Trauma

2

Imprimir a primeira palavra em uma string

Se a sequência estiver na variável ae não contiver caracteres de escape e formato ( \e %), use este:

printf $a

Mas seria maior que o código a seguir se for necessário salvar o resultado em uma variável em vez de imprimir:

x=($a)
$x

1

Fazendo 2 loop de incorporação com 1 forinstrução:

for ((l=i=0;l<=99;i=i>98?l++,0:++i)) ;do
    printf "I: %2d, L: %2d\n" $i $l
done |
    tee >(wc) | (head -n4;echo ...;tail -n 5)
I:  0, L:  0
I:  1, L:  0
I:  2, L:  0
I:  3, L:  0
...
I: 96, L: 99
I: 97, L: 99
I: 98, L: 99
I: 99, L: 99
  10000   40000  130000

1

Atribuir e imprimir strings entre aspas

Se você deseja atribuir uma string entre aspas a uma variável e depois imprimir o valor dessa variável, a maneira usual de fazer isso seria:

a="Programming Puzzles & Code Golf";echo $a

Se aanteriormente não estava definido, isso pode ser reduzido para:

echo ${a=Programming Puzzles & Code Golf}

Se afoi definido anteriormente, isso deve ser usado:

echo ${a+Programming Puzzles & Code Golf}

Observe que isso só é útil se a sequência exigir aspas (por exemplo, contém espaço em branco). Sem aspas, a=123;echo $aé tão curto.


${a+foo}não define a.
GammaFunction
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.