Consejos para jugar al golf en Bash

55

¿Qué consejos generales tienes para jugar al golf en Bash? Estoy buscando ideas que se puedan aplicar a los problemas de golf de código en general que sean al menos algo específicos para Bash (por ejemplo, "eliminar comentarios" no es una respuesta). Por favor, publique un consejo por respuesta.

hombre trabajando
fuente

Respuestas:

36

Sin documentar , pero funciona en todas las versiones con las que me he encontrado porshcompatibilidad con versiones anteriores:

forlos bucles le permiten usar en { }lugar de do done. Por ejemplo, reemplazar:

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

con:

for i in {1..10};{ echo $i;}
Trauma digital
fuente
¿Qué shell es shy qué shell permite esta forsintaxis? está expresamente permitido en zsh.
mikeserv
@mikeserv Bash. Recuerdo haber leído en alguna parte que esta sintaxis estaba permitida en algunos viejos shy que Bash también lo permite por eso, aunque lamentablemente no tengo una cita.
Trauma digital
ahh ... csh, probablemente, así es como trabajaron en ese caparazón.
mikeserv
por cierto, en ksh93lo anterior podría ser: ;{1..10}y en bash:printf %s\\n {1..10}
mikeserv
1
for((;i++<10)){ echo $i;}es más corto quefor i in {1..10};{ echo $i;}
Evan Krall
29

Para expansión aritmética, use en $[…]lugar de $((…)):

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

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

En expansiones aritméticas no 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

La expansión aritmética se realiza en subíndices de matriz indexados, por lo que no use $ninguno de ellos:

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

En expansiones aritméticas no 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
hombre trabajando
fuente
Reemplazar while((i--)), que funciona, con while[i--]o while $[i--]no funcionó para mí. GNU bash, versión 4.3.46 (1)
Glenn Randers-Pehrson el
1
Correcto, @ GlennRanders-Pehrson. Eso no se supone que funcione.
manatwork el
y=`bc<<<"($x*2.2)%10/1"`... ejemplo de uso bcpara cálculos no enteros ... tenga /1en cuenta que al final trunca el decimal resultante a un int.
roblogic
s=$((i%2>0?s+x:s+y))... ejemplo del uso del operador ternario en aritmética bash. Es más corto que if..then..elseo[ ] && ||
roblogic
1
@manatwork Gracias. Deben haberlo eliminado. Estoy encendido GNU bash, version 5.0.2(1)-release (x86_64-apple-darwin16.7.0)y no está en el mío.
Jonás
19

La forma normal, larga y aburrida de definir una función es

f(){ CODE;}

Como descubrió este tipo , absolutamente necesita el espacio antes CODEy el punto y coma después.

Este es un pequeño truco que aprendí de @DigitalTrauma :

f()(CODE)

Es dos caracteres más cortos y funciona igual de bien, siempre que no necesite trasladar ningún cambio en los valores de las variables después de que regrese la función ( los paréntesis ejecutan el cuerpo en una subshell ).

Como @ jimmy23013 señala en los comentarios, incluso los paréntesis pueden ser innecesarios.

El Manual de referencia de Bash muestra que las funciones se pueden definir de la siguiente manera:

name () compound-command [ redirections ]

o

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

Un comando compuesto puede ser:

  • una estructura iterativa: until, whileofor
  • un constructor condicional: if, case, ((...))o[[...]]
  • Comandos agrupados: (...)o{...}

Eso significa que todo lo siguiente es válido:

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

Y he estado usando llaves como una ventosa ...

Dennis
fuente
2
Tenga en cuenta que también puede usar f()while ... f()if ...y otros comandos compuestos.
jimmy23013
Este me sorprendió porque pensé que f()CODEera legal. Resulta que f()echo hies legal en pdksh y zsh, pero no en bash.
kernigh
1
es especialmente útil con el valor forpredeterminado de posicionales: f()for x do : $x; done;set -x *;PS4=$* f "$@"o algo así.
mikeserv
16

:es un comando que no hace nada, su estado de salida siempre tiene éxito, por lo que puede usarse en lugar de true.


fuente
Usando un subshell y tuberías, usaría aproximadamente el mismo número de bytes, pero las tuberías serían más prácticas.
ckjbgames
55
Excepto cuando lo haces:(){:|:}
enedil
14

Mas consejos

  1. Abusar del operador ternario, ((test)) && cmd1 || cmd2o [ test ] && cmd1 || cmd2, tanto como sea posible.

    Ejemplos (los recuentos de longitud siempre excluyen la línea superior):

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

    Al usar solo operadores ternarios, esto se puede acortar fácilmente a:

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

    Como nyuszika7h señaló en los comentarios, este ejemplo específico podría acortarse aún más usando case:

    t="$something"
    case $t in "hi")cmd1;cmd2;;"bye")cmd3;cmd4;;*)cmd5;[ $t == "sup" ]&&cmd6;esac
  2. Además, prefiera los paréntesis a las llaves tanto como sea posible. Como los paréntesis son metacaracteres y no una palabra, nunca requieren espacios en ningún contexto. Esto también significa ejecutar tantos comandos en una subshell como sea posible, porque las llaves (es decir, {y }) son palabras reservadas, no metacaracteres, y por lo tanto deben tener espacios en blanco en ambos lados para analizar correctamente, pero los metacaracteres no lo hacen. Supongo que ya sabe que las subcapas no afectan el entorno principal, por lo que suponiendo que todos los comandos de ejemplo se puedan ejecutar de forma segura en una subcapa (lo cual no es típico en ningún caso), puede acortar el código anterior a esto :

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

    Además, si no puede hacerlo, usar paréntesis aún puede minimizarlo. Una cosa a tener en cuenta es que solo funciona para enteros, lo que lo hace inútil para los propósitos de este ejemplo (pero es mucho mejor que usar -eqpara enteros).

  3. Una cosa más, evite las comillas siempre que sea posible. Usando ese consejo anterior, puedes minificarlo aún más. Ejemplo:

    t=$something
    [ $t == hi ]&&(cmd1;cmd2)||[ $t == bye ]&&(cmd3;cmd4)||(cmd5;[ $t == sup ]&&cmd6)
  4. En condiciones de prueba, prefiera corchetes simples a corchetes dobles tanto como sea posible, con algunas excepciones. Deja caer dos caracteres de forma gratuita, pero en algunos casos no es tan robusto (es una extensión de Bash; vea un ejemplo a continuación). Además, use el argumento de igual simple en lugar del doble. Es un personaje libre 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 -

    Tenga en cuenta esta advertencia, especialmente al verificar la salida nula o una variable indefinida:

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

    En todos los aspectos técnicos, este ejemplo específico sería mejor con case... in:

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

Entonces, la moraleja de esta publicación es esta:

  1. Abusar de los operadores booleanos tanto como sea posible, y usarlos siempre en lugar de if/ if-else/ etc. construcciones
  2. Use paréntesis tanto como sea posible y ejecute tantos segmentos como sea posible en subcapas porque los paréntesis son metacaracteres y no palabras reservadas.
  3. Evite las citas tanto como sea físicamente posible.
  4. Echa un vistazo case... in, ya que puede ahorrar bastantes bytes, particularmente en la coincidencia de cadenas.

PD: Aquí hay una lista de metacaracteres reconocidos en Bash independientemente del contexto (y puede separar palabras):

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

EDITAR: Como señaló manatwork, la prueba de paréntesis doble solo funciona para enteros. Además, indirectamente, descubrí que necesitas tener espacios en blanco alrededor del ==operador. Corregí mi publicación anterior.

También era demasiado vago para volver a calcular la longitud de cada segmento, así que simplemente los eliminé. Debería ser fácil encontrar una calculadora de longitud de cadena en línea si es necesario.

Isiah Meadows
fuente
Lamento decirlo, pero tiene algunos errores graves allí. [ $t=="hi" ]siempre se evaluará a 0, ya que se analiza como [ -n "STRING" ]. (($t=="hi"))siempre se evaluará a 0 siempre que $ t tenga un valor no numérico, ya que las cadenas se convierten en enteros en las evaluaciones aritméticas. Algunos casos de prueba: pastebin.com/WefDzWbL
manatwork
@manatwork Gracias por la captura. Actualizaré en consecuencia.
Isiah Meadows
Usar a casesería más corto aquí. Además, no necesita un espacio antes }, pero sí después {.
nyuszika7h
1
¿Por qué sería =menos robusto que ==? =es un mandato de POSIX, ==no lo es.
Dennis
1
La pregunta pide un consejo por respuesta ...
Toby Speight
7

En lugar de grep -E, grep -F, grep -r, uso egrep, fgrep, rgrep, ahorrando dos caracteres. Los más cortos están en desuso pero funcionan bien.

(¡Pidió un consejo por respuesta!)


fuente
1
Lástima que no hay Pgreppara grep -P. Aunque veo cómo podría confundirse fácilmente con esto pgrep, que se utiliza para buscar procesos.
nyuszika7h
1
@ nyuszika7h Yo personalmente uso grep -omucho
¿No ahorraría 3 incluyendo el espacio?
ckjbgames
7

Se puede acceder al elemento 0 de una matriz solo con el nombre de la variable, un ahorro de cinco bytes que especifica explícitamente un índice de 0:

$ a=(code golf)
$ echo ${a[0]}
code
$ echo $a
code
$ 
Trauma digital
fuente
7

Si necesita pasar el contenido de una variable a STDIN del siguiente proceso en una tubería, es común hacer eco de la variable en una tubería. Pero puedes lograr lo mismo con una <<< cadena bash here :

$ s="code golf"
$ echo "$s"|cut -b4-6
e g
$ cut -b4-6<<<"$s"
e g
$ 
Trauma digital
fuente
2
Ya que estamos golf, s=code\ golf, echo $s|y <<<$s(teniendo en cuenta que estos dos últimos trabajos sólo porque hay espacios sin repetidas, etc.).
Dennis
6

Evita $( ...command... ), hay una alternativa que ahorra un personaje y hace lo mismo:

` ...command... `

fuente
99
A veces $( )es necesario si tiene sustituciones de comandos anidadas; de lo contrario, tendría que escapar del interior``
Digital Trauma
1
Estos técnicamente hacen cosas diferentes, he tenido que usar los backticks en lugar de $()cuando quería ejecutar la sustitución en mi máquina en lugar de la scpmáquina de destino, por ejemplo. En la mayoría de los casos son idénticos.
undergroundmonorail
2
@undergroundmonorail: nunca necesitas backticks. Cualquier cosa que puedan hacer, $()puede hacer si cita las cosas correctamente. (a menos que necesite su comando para sobrevivir a algo que explota $pero no retrocede). Hay algunas diferencias sutiles en citar cosas dentro de ellos. mywiki.wooledge.org/BashFAQ/082 explica algunas diferencias. A menos que esté jugando al golf, nunca use backticks.
Peter Cordes
@PeterCordes Estoy seguro de que era una manera, pero todo lo que probé en el momento no ha funcionado. Incluso si los backticks no eran la mejor solución, me alegré de saberlos porque era la única solución que tenía. ¯ \ _ (ツ) _ / ¯
undergroundmonorail
@DigitalTrauma Muestra de anidamiento: echo `bc <<<"\`date +%s\`-12"`... (¡Es difícil publicar una muestra que contenga una marca de retroceso en el comentario, allí!)
F. Hauri
6

Usar ifpara agrupar comandos

En comparación con este consejo que elimina iftodo, esto solo debería funcionar mejor en algunos casos muy raros, como cuando necesita los valores de retorno de if.

Si tiene un grupo de comandos que termina con un if, como estos:

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

En su lugar, puede ajustar los comandos antes ifen la condición:

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

O si su función termina con un if:

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

Puedes quitar las llaves:

f()if a;b;then c;else d;fi
jimmy23013
fuente
1
Puede usar el operador ternario [test] && $if_true || $elseen estas funciones y guardar algunos bytes.
ckjbgames
Además, no necesita espacios alrededor &&y||
roblogic
6

Use aritmética (( ... ))para condiciones

Podrías reemplazar:

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: no hay espacio después if)

o incluso

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

... o si solo un comando

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

Además: Ocultar configuración de variable en construcción aritmética:

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

o igual

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

... donde si i> 5, entonces c = 1 (no 0;)

F. Hauri
fuente
Puede guardar 2 bytes usando en [ ]lugar de (()).
ckjbgames
@ckjbgames ¿Estás seguro de eso? ¿Qué versión de bash estás usando?
F. Hauri
@FHauri Supongo que sería casi lo mismo en términos de bytes.
ckjbgames
@ckjbgames Con [ ]usted necesita el signo de dólar para variable. No veo cómo podría hacer lo mismo con una longitud igual o menor usando [ ].
F. Hauri
Consejo adicional: si comienza la primera línea de un bucle for ((...)), no es necesaria una nueva línea o espacio. Por ejemplo, for((;10>n++;)){((n%3))&&echo $n;} pruébelo en línea.
primo
6

Una sintaxis más corta para bucles infinitos (que se puede escapar con breako exitdeclaraciones) es

for((;;)){ code;}

Esto es más corto que while true;y while :;.

Si no lo necesita break( exitcomo la única forma de escapar), puede usar una función recursiva en su lugar.

f(){ code;f;};f

Si necesita un descanso, pero no necesita salir y no necesita trasladar ninguna modificación de variable fuera del ciclo, puede usar una función recursiva con paréntesis alrededor del cuerpo , que ejecuta el cuerpo de la función en una subshell.

f()(code;f);f
Gilles 'SO- deja de ser malvado'
fuente
6

forBucles de una línea

Se evaluará una expresión aritmética concatenada con una expansión de rango para cada elemento del rango. Por ejemplo lo siguiente:

: $[expression]{0..9}

evaluará expression10 veces.

Esto suele ser significativamente más corto que el forbucle equivalente :

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

Si no le importa los errores de comando no encontrado, puede eliminar el inicial :. Para iteraciones mayores de 10, también puede usar rangos de caracteres, por ejemplo {A..z}, iterará 58 veces.

Como ejemplo práctico, los siguientes dos producen los primeros 50 números triangulares, cada uno en su propia línea:

for((;50>d++;)){ echo $[n+=d];} # 31 bytes
printf %d\\n $[n+=++d]{A..r}    # 28 bytes
primo
fuente
También puede iterar hacia atrás:for((;0<i--;)){ f;}
roblogic
5

Recorrer argumentos

Como se señaló en el bucle Bash "for" sin una parte "in foo bar ..." , el in "$@;"in for x in "$@;"es 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 ejemplo, si queremos cuadrar todos los números dados argumentos posicionales a un script Bash o una función, podemos hacer esto.

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

Pruébalo en línea!

Dennis
fuente
5

Alternativa al gato

Digamos que está intentando leer un archivo y usarlo en otra cosa. Lo que puedes hacer es:

echo foo `cat bar`

Si el contenido de barwas foobar, esto se imprimiría foo foobar.

Sin embargo, existe una alternativa si está utilizando este método, que ahorra 3 bytes:

echo foo `<bar`
Okx
fuente
1
¿Hay alguna razón <barpor la cual por sí solo no funciona, pero si lo coloca en backticks sí?
Kritixi Lithos
@Cowsquack Sí. El <pone un archivo a un comando, pero en este caso se pone en la salida estándar, debido a una peculiaridad. Los backticks evalúan esto juntos.
Okx
¿Existe una forma más corta de leer desde la entrada estándar que no sea `cat`?
Joel
4

Usar en [lugar de [[y testcuando sea posible

Ejemplo:

[ -n $x ]


Usar en =lugar de ==para comparar

Ejemplo:

[ $x = y ]

Tenga en cuenta que debe tener espacios alrededor del signo igual o de lo contrario no funcionará. Lo mismo aplica ==basado en mis pruebas.

nyuszika7h
fuente
3
El [vs. [[puede depender de la cantidad de cotizaciones requeridas: pastebin.com/UPAGWbDQ
manatwork
@manatwork Ese es un buen punto.
nyuszika7h
1
Regla general: [... ]== /bin/test, pero [[... ]]! = /bin/testY uno nunca debería preferir [... ]a [[... ]]fuera de codegolf
cat
4

Alternativas a head

linees tres bytes más corto que head -1, pero está en desuso .

sed qes dos bytes más corto que head -1.

sed 9qes un byte más corto que head -9.

Lynn
fuente
1
Aunque condenada , aún podemos usar por un tiempo linede util-linux paquete para leer una sola línea.
manatwork
4

tr -cd es más corto que grep -o

Por ejemplo, si necesita contar espacios, grep -o <char>(imprimir solo el coincidente) da 10 bytes mientras que tr -cd <char>(eliminar complemento de <char>) da 9.

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

( fuente )

Tenga en cuenta que ambos dan resultados ligeramente diferentes. grep -odevuelve resultados separados por líneas mientras los tr -cdda a todos en la misma línea, por lo que trpuede no ser siempre favorable.

Kritixi Lithos
fuente
4

Acortar nombres de archivo

En un desafío reciente, estaba tratando de leer el archivo /sys/class/power_supply/BAT1/capacity, sin embargo, esto se puede acortar /*/*/*/*/capac*yya que no existe ningún otro archivo con ese formato.

Por ejemplo, si tenía un directorio que foo/contenía los archivos foo, bar, foobar, barfooy deseaba hacer referencia al archivo foo/barfoo, puede usarlo foo/barf*para guardar un byte.

El *representa "cualquier cosa", y es equivalente a la expresión regular .*.

Okx
fuente
3

Use una tubería para el :comando en lugar de /dev/null. El :incorporado comerá toda su entrada.


fuente
2
No, bloqueará el programa con SIGPIPE en la mayoría de los casos. echo a|tee /dev/stderr|:No imprimirá nada.
jimmy23013
Hay una carrera: echo a|tee /dev/stderr|:imprimí un en mi computadora, pero en otro lugar SIGPIPE podría matar el tee primero. Puede depender de la versión de tee.
kernigh
Sí, es un problema SIGPIPE: tee >(:) < <(seq 1 10)funcionará, pero tee /dev/stderr | :no lo hará. Incluso a() { :;};tee /dev/stderr < <(seq 1 10)| ano imprima nada.
F. Hauri
@ user16402 - deberías tener un nombre fccing a mi alcance ... de todos modos, el :intrínseco no se come en absoluto ... si supones una entrada a los dos puntos, podrías inundar una tubería en un error ... pero puedes flotar una redirección por dos puntos, o dejar caer un proceso con él ... :| while i>&$(($??!$?:${#?})) command shit; do [ -s testitsoutput ]; doneo, sin embargo, esa pseudo sugerencia se aplica ... también, ¿eres consciente de que eres tan fantasmal como yo? ... evitar a toda costa el< <(psycho shit i can alias to crazy math eat your world; okay? anyway, ksh93 has a separate but equal composite char placement)
mikeserv
3

splittiene otra sintaxis (en desuso, pero a nadie le importa) para dividir la entrada en secciones de Nlíneas cada una: en lugar de split -lNque pueda usar, split -Npor ejemplo split -9.


fuente
3

Expande las pruebas

Esencialmente, el shell es un tipo de lenguaje macro, o al menos un híbrido o algún tipo. Cada línea de comando se puede dividir básicamente en dos partes: la parte de análisis / entrada y la parte de expansión / salida.

La primera parte es en lo que la mayoría de la gente se enfoca porque es la más simple: ves lo que obtienes. La segunda parte es lo que muchos evitan incluso tratar de entender muy bien y es por qué la gente dice que las cosas evalson malas y siempre citan sus expansiones : la gente quiere que el resultado de la primera parte sea igual a la primera. Eso está bien, pero conduce a ramificaciones de código innecesariamente largas y toneladas de pruebas extrañas.

Las expansiones son de autoevaluación . Los ${param[[:]#%+-=?]word}formularios son más que suficientes para validar el contenido de un parámetro, son anidables y se basan en la evaluación de NUL , que es lo que la mayoría de la gente espera de las pruebas de todos modos. +puede ser especialmente útil en bucles:

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

... mientras readlas líneas no en blanco se "${r:+set}"expanden "set"y las posiciones se $ragregan. Pero cuando una línea en blanco es read, $restá vacía y se "${r:+set}"expande a "", que es un comando no válido. Pero debido a que la línea de comandos se expande antes de la ""se busca comando nulo, "${r:=$*}"toma los valores de todos los posicionales concatenados en el primer byte $IFStambién. r()podría llamarse nuevamente en un |{comando compuesto ;}con un valor diferente para $IFSobtener el siguiente párrafo de entrada, ya que es ilegal que un shell se almacene readmás allá de la siguiente \nlínea de entrada.

mikeserv
fuente
3

Use la recursión de la cola para acortar los bucles:

Estos son equivalentes en comportamiento (aunque probablemente no en uso de memoria / PID):

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

Y estos son más o menos equivalentes:

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

(técnicamente los últimos tres siempre ejecutarán el cuerpo al menos una vez)

El uso $0requiere que su script esté en un archivo, no pegado en el indicador bash.

Finalmente, su pila puede desbordarse, pero guarda algunos bytes.

Evan Krall
fuente
3

A veces es más corto usar el valor exprincorporado para mostrar el resultado de una expresión aritmética simple en lugar de la habitual echo $[ ]. Por ejemplo:

expr $1 % 2

es un byte más corto que:

echo $[$1%2]
Trauma digital
fuente
2

Use en pwdlugar de echogenerar una línea de salida

¿Necesita poner una línea en stdout pero no le importan los contenidos y desea restringir su respuesta a los componentes integrados de shell? pwdes un byte más corto que echo.

Glenn Randers-Pehrson
fuente
2

Las citas pueden omitirse al imprimir cadenas.

echo "example"
echo example

Salida en SM-T335 LTE, Android 5.1.1:

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

fuente
2

Al asignar elementos de matriz no continuos, aún puede omitir los índices sucesivos de fragmentos continuos:

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)

El resultado es el mismo:

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 acuerdo a man bash:

Las matrices se asignan al uso de asignaciones compuestas de la forma nombre = (valor 1 ... valor n ), donde cada valor es de la forma [ subíndice ] = cadena . Las asignaciones de matriz indexadas no requieren nada más que una cadena . Al asignar a matrices indexadas, si se proporcionan los corchetes opcionales y el subíndice, ese índice se asigna a; de lo contrario, el índice del elemento asignado es el último índice asignado por la instrucción más uno.

hombre trabajando
fuente
Útil para agregar: los elementos no inicializados se expandirán a 0 en expansiones aritméticas y "" en otras expansiones.
Trauma digital
2

Imprime la primera palabra en una cadena

Si la cadena está en la variable ay no contiene caracteres de escape y formato ( \y %), use esto:

printf $a

Pero sería más largo que el siguiente código si fuera necesario para guardar el resultado en una variable en lugar de imprimirlo:

x=($a)
$x
jimmy23013
fuente
1

Hacer 2 bucles de inserción con 1 forinstrucción:

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
F. Hauri
fuente
1

Asignar e imprimir cadenas entre comillas

Si desea asignar una cadena entre comillas a una variable y luego imprimir el valor de esa variable, la forma habitual de hacerlo sería:

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

Si no ase configuró anteriormente, esto se puede acortar a:

echo ${a=Programming Puzzles & Code Golf}

Si ase configuró previamente, entonces debería usarse en su lugar:

echo ${a+Programming Puzzles & Code Golf}

Tenga en cuenta que esto solo es útil si la cadena requiere comillas (por ejemplo, contiene espacios en blanco). Sin comillas, a=123;echo $aes igual de breve.

Trauma digital
fuente
${a+foo}no fija a.
GammaFunction