g | x | w | all
Bytes Lang Time Link
nan231101T145229ZShadowRa
nan140215T030500ZClaudia
nan230223T231215ZShadowRa
nan180621T203844Zuser4180
nan211120T053723ZNate T
nan211120T091213Zuser1004
nan211111T211221Zpxeger
nanIn Pure Bash or any other pure shellscript211111T105825Zuser1004
nan210803T161859Zpxeger
nan210803T155127Zpxeger
nanTo print a range of characters shorter than echo {a..z}|tr d ' '191122T105136Zbuilder-
nan190907T214028ZGammaFun
nan190202T102447ZF. Hauri
nan190202T104624ZF. Hauri
002In a case statement180721T131131ZBastian
nan181124T111842Zprimo
nan181019T160116ZDigital
nan180730T211839ZOkx
nan180802T002031ZDigital
nan180730T212025ZOkx
nan180115T194039ZDennis
nan171202T150721ZF. Hauri
nan170724T102132Zjimmy230
nanUndocumented140413T041447ZDigital
nanWhen assigning noncontinuous array items170629T101320Zmanatwor
nan141107T034030ZDennis
nan140603T202240Zuser1640
nan170127T230237Zlynn
nan160108T231154ZF. Hauri
nan170119T044558ZEvan Kra
nan170105T185613Zuser6391
nan161106T210430ZGlenn Ra
nan151224T150648Zmikeserv
nan150330T104554Zjimmy230
nanIf you need to pass the content of a variable to STDIN of the next process in a pipeline141106T231936ZDigital
000Element 0 of an array may be accessed with the variable name only141106T231314ZDigital
009split has another deprecated140603T201947Zuser1640
nanAvoid $ ...command...140409T134517Zuser1640
nan140603T201816Zuser1640
nan140421T192659Zuser344
nanInstead of grep E140409T135215Zuser1640
nan is a command that does nothing140409T134718Zuser1640
nan131115T091411Zmanatwor

Compress long runs of decimal digits using alternate base representation

bash's arithmetic context supports numbers in arbitrary alternate bases more compactly that any other language I know of (e.g. Python's int(string,base) has overhead of six characters for the int, (, ), and ,, if you aren't given the string from elsewhere, two more for the ' or " around the literal, plus 1-2 characters for the base). By contrast, bash only needs three characters to impose arithmetic context, $[] (if you're not already in it), and just one character to impose alternate base context, and the same 1-2 characters for the base, so bash needs 2-6 characters to do what Python (which is relatively good on this score) needs 6-9 characters to do.

Bash also supports higher bases for integer literals than most languages (topping out at base 64, rather than base 36 as is common; if you use a base above 36, it uses a digit "alphabet" of up to 0-9a-zA-Z@_).

Between these two features, you can shave up to three characters off long strings of decimal digits by replacing them with arithmetic context (using the shorter form of arithmetic expansion) of a base 64 value. The best savings occur when the digits in question require an even multiple of six bits to represent in binary, and no savings are available unless the decimal representation of the integer is at least 15 characters long, but when it works, it's a great way to shorten further. If you're using it as a number in an existing arithmetic context that does other math, you can save up to 6 characters (since the $[] is already paid for by the need to do math, so it doesn't count against the cost of the alternate base), and benefits begin to appear at just 8 decimal digits.

For the best case scenario, a program that needs a literal string numerically equivalent to a number between (with _ for readability) 1_000_000_000_000_000_000 and 1_152_921_504_606_846_975 can represent such a number as either:

1000000000000000000
# or shaving three characters
$[64#TwJHeDp000]

If you were already in arithmetic context, it saves six instead:

$[var%1000000000000000000]
# becomes
$[var%64#TwJHeDp000]

NB: Here's a bash script to convert a decimal number like 1000000000000000000 to the radix 64 representation above (this is NOT base64 encoding, it's just converting number formats).

A=({0..9} {a..z} {A..Z} @ _)
for x in `bc<<<"obase=64;1000000000000000000"`;{ printf ${A[x]};}

More tips

  1. Abuse the ternary operator, ((test)) && cmd1 || cmd2 or [ test ] && cmd1 || cmd2, as much as possible.

Examples (length counts always exclude the top line):

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

By using ternary operators only, this can easily be shortened to:

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

As nyuszika7h pointed out in the comments, this specific example could be shortened even further using case:

    t="$something"
    case $t in "hi")cmd1;cmd2;;"bye")cmd3;cmd4;;*)cmd5;[ $t == "sup" ]&&cmd6;esac
  1. Also, prefer parentheses to braces as much as possible. Since parentheses are a metacharacter, and not a word, they never require spaces in any context. This also means run as many commands in a subshell as possible, because curly braces (i.e. { and }) are reserved words, not meta-characters, and thus have to have whitespace on both sides to parse correctly, but meta-characters don't. I assume that you know by now that subshells don't affect the parent environment, so assuming that all the example commands can safely be run in a subshell (which isn't typical in any case), you can shorten the above code to this:

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

Also, if you can't, using parentheses can still minify it some. One thing to keep in mind is that it only works for integers, which renders it useless for the purposes of this example (but it is much better than using -eq for integers).

  1. One more thing, avoid quotes where possible. Using that above advice, you can further minify it. Example:

     t=$something
     [ $t == hi ]&&(cmd1;cmd2)||[ $t == bye ]&&(cmd3;cmd4)||(cmd5;[ $t == sup ]&&cmd6)
    
  2. In testing conditions, prefer single brackets to double brackets as much as possible with a few exceptions. It drops two characters for free, but it isn't as robust in some cases (it's a Bash extension - see below for an example). Also, use the single equals argument rather than the double. It is a free character to drop.

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

Note this caveat, especially in checking for null output or an undefined variable:

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

In all technicality, this specific example would be best with case ... in:

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

So, the moral of this post is this:

  1. Abuse the boolean operators as much as possible, and always use them instead of if/if-else/etc. constructs.
  2. Use parentheses as much as possible and run as many segments as possible in subshells because parentheses are meta-characters and not reserved words.
  3. Avoid quotes as much as physically possible.
  4. Check out case ... in, since it may save quite a few bytes, particularly in string matching.

P.S.: Here's a list of meta-characters recognized in Bash regardless of context (and can separate words):

< > ( ) ; & | <space> <tab>

EDIT: As manatwork pointed out, the double parenthesis test only works for integers. Also, indirectly, I found that you need to have whitespace surrounding the == operator. Corrected my post above.

I also was too lazy to recalculate the length of each segment, so I simply removed them. It should be easy enough to find a string length calculator online if necessary.

Output a string based on a test string or numeric test with expr

From my question: For any form of test expr supports (numerical or string equality, inequality, less than, greater than, regex pattern match, with support for math), there are often ways to use it to improve on the naive approach to echoing a particular string based on a given test. For example, the most straightforward approach to performing an "is a program argument a substring of a fixed string?" test, echoing the string true or false based on the result, assuming the substring contains no regex special characters, is:

[[ FIXEDSTRING =~ $1 ]]&&echo true||echo false

But with expr, we can shave off six characters by careful use of & and | to select the string that results from the overall test:

expr true \& FIXEDSTRING : .*$1 \| false

Changing the * to \* (and costing a character) if there is a possibility that the command will be run in a directory where .*$1 would match existing files.

The ordering is important here; \& evaluates to the first argument (not the second like in Python and similar language) when the overall "and" expression is true, so true \& must come before the pattern match test FIXEDSTRING : .*$1. The .* is needed because pattern matching is implicitly anchored at the beginning, as with ^, so the .* lets it match anywhere. And no, sadly, you can't remove any of these spaces; expr expects each operand and operator to be a completely separate argument, so it doesn't need to do any tokenizing of its own, which means the spaces must be there so the shell can tokenize it.

For the specific case of a regex match, you can shorten it four more characters with sed, :

sed "/$1/ctrue
cfalse"<<<FIXEDSTRING

Similar uses allow replacing the various forms of numerical test and echo:

[ $1 -gt 0 ]&&echo yes||echo no
[[ $1>0 ]]&&echo yes||echo no
(($1>0))&&echo yes||echo no

with:

expr yes \& $1 \> 0 \| no

which, even with the need to escape the >, and despite numerical tests with (()) allowing you to drop all whitespace, is still two characters shorter than the shortest of the naive approaches. If the comparison is more complex, you can mix-and-match:

expr yes \& $[$1>0] \| no

is the same length as the purely expr-based approach, but grows more slowly in more complex cases (as fewer things need escaping, and spaces aren't needed between terms).

tr -cd is shorter than grep -o

For example, if you need to count spaces, grep -o <char> (print only the matched) gives 10 bytes while tr -cd <char> (delete complement of <char>) gives 9.

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

(source)

Note that they both give slightly different outputs. grep -o returns line separated results while tr -cd gives them all on the same line, so tr might not always be favourable.

ONE-LINE CONDITIONAL SETTER

NOTE: I see now that this first bit is already present on the first page, so I updated to add another tip (below the phrase 'EDIT-POINT:') which adds to the initial syntax to achieve a different outcome.

Here is a super efficient way to do control statements in bash.

instead of

if [ -e "${var}" ]
then
   echo "${var}"
else
   echo "empty"
fi

which translates to the one-liner:

if [ -e "${var}" ]; then echo "${var}"; else echo "empty"; fi

...you can use logical and / or like so:

[ -e "${var}" ] && echo "${var}" || echo "empty"

The second bit runs only if the first bit returns a 0 exit code. If either of the first two bits fail to exit with 0 (in other words, if false when used with [] / test command), the third bit runs. This means that in production / distribution use cases, this form is often a bad idea (if the if logic runs but fails fails, the else statement runs..), but for code golf, it is ore than sufficient, so long as you test it on the command line first.

It also works with the if / && (no else / ||), e.g.

[ -e "${var}" ] && echo "${var}"

if that is what you need. This version runs exactly as the long form, without the caveat mentioned above.

EDIT-POINT:

Another advantage of using this syntax is that you can put the entire command inside a variable. When you need to set a variable to a value that is based on a condition, this saves a lot of space.

For example,

if [ -e "${var}" ]
then
   TEXT="${var}"
else
    TEXT="empty"
fi

can be dropped to:

TEXT=$([ -e "${var}" ] && echo "${var}" || echo "empty")

As a code golf tip, this has limited uses, but they do exist. The space gained or lost depends on the size of the variable name. It adds up to the same as setting a four-letter variable (so ends in unity in the example above.)

Since we use single-letter variable names in code golf, this normally doesn't save any space at all. The space saving effect kicks in when we have no control over the name, in cases where we are using an environment variable in a cheeky way, or when a variable name is provided via a constraint in the question.

Know grep options

See also man 1p grep and manual for GNU Grep.

grep -x foo is equivalent to grep '^foo$

This is POSIX-compatible.

Consider only input lines that use all characters in the line excluding the terminating <newline> to match an entire fixed string or regular expression to be matching lines.

For example, the following two are equal:

grep -E '^abc$|^def$'
grep -F -x 'abc
def'

Use $_ (the underscore variable)

The special shell variable $_ always contains the last argument to the most recently executed command. If you have any sort of immediate repetition in your code, it can probably be reduced with this.

touch hello;cat hello
touch hello;cat $_

More details can be found in this Unix & Linux question.

(I can't believe this hasn't been posted before, and, as far as I can tell, barely ever even been used in code golf before!)

In Pure Bash (or any other pure shellscript), use . for looping.

For example, if you want to display each value of 1^2, 2^2, 3^2, ..., 999^2, 1000^2,

echo $[++x*x]
((x>999))||. x

(where filename is x) is shorter than

for((;x++<1000;));{
echo $[x*x]
}

Try it online!

Abuse function definitions to check for equality

If you want to check if two strings are equal to each other, the obvious way is to use the [[/test/[ builtins:

[[ $a == b ]]
[[ $a = b ]]
[ $a = b ]

But in fact often a shorter way is to define a do-nothing function under the name of b and then try to call it with $a.

b()(:);$a
# zsh only:
b():;$a

Depending on the possible values $a can take, you might need to add some characters to ensure that it never coincides with the name of a real command:

,b()(:);,$a
# zsh only:
,b();,$a

If you're testing and immediately using &&, then you can put generally put the command after the && as the body of the function:

[ $a = b ]&&foo
b()(foo);$a
# zsh only:
b()foo;$a

Here are a few answers I've abused this in (Zsh not Bash, but the same idea applies):

Use {..} expansions with eval

Occasionally loops can be shortened by using eval with a brace expansion. For example, to run a command foo with all letters a-z sequentially; instead of:

for x in {a..z};{ foo $x;}
# or, zsh only:
for x ({a..z})foo $x
eval foo\ {a..z}\;
# or, zsh only:
eval ';foo '{a..z}

If you need to reuse the loop variable, it tends to be shorter to use a normal for-loop though.

I can't remember exactly the first answer I saw to do this, but I now use it a lot (those examples are all Zsh because it's obviously superior to Bash, but it's a similar general idea).

To print a range of characters (shorter than echo {a..z}|tr -d ' '):

printf "%s" {a..z}

Print range in reverse order (shorter than printf "%s" {a..z}|rev):

printf "%s" {z..a}

It is almost always better to receive input as arguments to a script or function instead of on stdin. Examples:

Input: a string:

# == stdin ==
read a;echo $a
echo `<&0`
# == arguments ==
echo "$1"       # if $1 can have globbing characters/newlines/tabs
echo $1         # if $1 does not have any problematic characters

Input: a list of strings:

# == stdin ==
while read s; do echo $s; done          # one-time use, split on newlines
read -a a;for s in ${a[@]};{echo $s;}   # read one line from stdin; splits on spaces
mapfile a;for s in "${a[@]}";{echo $s;} # read to EOF, split on newlines
# == arguments ==
for s;{ echo $s;}

The exception: a list of strings and other arguments:

read i;while read s; do echo ${s[$i]}; done   # both on stdin
i=$1;shift;for s;{ echo ${s[$i]};}            # both as arguments
read i;for s;{ echo ${s[$i]};}                # list as arguments, other as stdin

Additionally, read will mangle backslashes without -r, and will stop on newlines without -d '', making it even more expensive in worst case scenarios.

This work under simple shell

cd `mktemp -d` &&>'c'a't'
ln -s /proc/loadavg /proc/uptime .

Then now

procs=$(*)
echo $procs
0.30 0.08 0.03 1/612 31671 322787.60 1259967.99

Nota: Of course, >cat could be written >$(echo -e \\0143\\0141t)

Care, from there, you could encouter some issues due to Locales!

Goto last demo using LC_ALL=C

Same way:

mv cat grep
mv loadavg Mem
ln -s /proc/meminfo Zdatas
rm uptime

mems=$(*)
echo $mems 
MemTotal: 16386788 kB MemFree: 9816320 kB MemAvailable: 12144892 kB

or worst...

mv grep sed
mv Mem s+\\\(Mem\\\|Swap\\\).\*\:++p\;d

then

memsw=$(*)
echo $memsw 
16386788 kB 9834080 kB 12163596 kB 0 kB 20971516 kB 20971516 kB

So simple is this!

declare -p procs mems memsw
declare -- procs="0.14 0.12 0.05 1/612 32078
324221.56 1265616.26"
declare -- mems="MemTotal:       16386788 kB
MemFree:         9832212 kB
MemAvailable:   12161688 kB"
declare -- memsw="       16386788 kB
         9834080 kB
   12163596 kB
            0 kB
      20971516 kB
       20971516 kB"

Last test using LANG=C

(or not)

cd `mktemp -d` &&>'c'a't'
ln -s /proc/meminfo zdatas
cp c* y+-+-+\;s+\\\(Mem\\\|Swap\\\).\*\:\ \*++p\;d
rename 'y/act/esd/' ???
*

may render something like

378908 kB
31940 kB
217924 kB
0 kB
102396 kB
102396 kB

Or

cd `mktemp -d`
ln -s +++\;s+\\\(Mem\\\|Swap\\\).\*\:\ \*++p\;d /proc/me*o ed .
rename 's/^/chr(113+(20>length?1.3*length:8))/e' *
*

Changing behaviour of += by setting integer flag

Try this many times:

unset i
i=1
for a in {1..10} ;do
    i+=1
    ((RANDOM%9)) || declare -i i
  done
echo $i
11117

or in one line

unset i;i=1;for a in {1..10};do i+=1;((RANDOM%9))||declare -i i;done;echo $i

This could answer something between 20 to 11111111111...

In a case statement, it is valid to omit the last ';;' - which saves 2 bytes:

#!/bin/sh

case $I in
0)cmdA;;
1)cmdB;;
*)cmdC
esac

One-line for loops

An arithmetic expression concatenated with a range expansion will be evaluated for each item in the range. For example the following:

: $[expression]{0..9}

will evaluate expression 10 times.

This is often significantly shorter than the equivalent for loop:

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

If you don't mind command not found errors, you can remove the inital :. For iterations larger than 10, you can also use character ranges, for example {A..z} will iterate 58 times.

As a practical example, the following both produce the first 50 triangular numbers, each on their own line:

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

Assign and Print quoted strings

If you want to assign a quoted string to a variable, and then print the value of that variable, then the usual way to do that would be:

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

If a was previously unset, this may be shortened to:

echo ${a=Programming Puzzles & Code Golf}

If a was previously set, then this should be used instead:

echo ${a+Programming Puzzles & Code Golf}

Note this is only useful if the string requires quotes (e.g. contains whitespace). Without quotes, a=123;echo $a is just as short.

Shorten file names

In a recent challenge I was trying to read the file /sys/class/power_supply/BAT1/capacity, however this can be shortened to /*/*/*/*/capac*y as no other file exists with that format.

For example, if you had a directory foo/ containing the files foo, bar, foobar, barfoo and you wanted to reference the file foo/barfoo, you can use foo/barf* to save a byte.

The * represents "anything", and is equivalent to the regex .*.

Sometimes it is shorter to use the expr builtin for displaying the result of a simple arithmetic expression instead of the usual echo $[ ]. For example:

expr $1 % 2

is one byte shorter than:

echo $[$1%2]

Alternative to cat

Say you are trying to read a file and use it in something else. What you might do is:

echo foo `cat bar`

If the contents of bar was foobar, this would print foo foobar.

However, there is an alternative if you are using this method, which saves 3 bytes:

echo foo `<bar`

Loop over arguments

As noted in Bash “for” loop without a “in foo bar…” part, the in "$@;" in for x in "$@;" is redundant.

From 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.

For example, if we want to square all numbers given positional arguments to a Bash script or a function, we can do this.

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

Try it online!

Doing 2 embed loop with 1 for instruction:

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

Print the first word in a string

If the string is in the variable a and doesn't contain escape and format characters (\ and %), use this:

printf $a

But it would be longer than the following code if it is needed to save the result into a variable instead of printing:

x=($a)
$x

Undocumented, but works in every version I've run into for legacy sh backwards compatibility:

for loops allow you to use { } instead of do done. E.g. replace:

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

with:

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

When assigning noncontinuous array items, you can still skip the successive indices of continuous chunks:

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)

The result is the same:

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")

According to man bash:

Arrays are assigned to using compound assignments of the form name=(value1 ... valuen), where each value is of the form [subscript]=string. Indexed array assignments do not require anything but string. When assigning to indexed arrays, if the optional brackets and subscript are supplied, that index is assigned to; otherwise the index of the element assigned is the last index assigned to by the statement plus one.

The normal, lengthy and boring way to define a function is

f(){ CODE;}

As this guy found out, you absolutely need the space before CODE and the semicolon after it.

This is a little trick I've learned from @DigitalTrauma:

f()(CODE)

That is two characters shorter and it works just as well, provided that you don't need to carry over any changes in variables' values after the function returns (the parentheses run the body in a subshell).

As @jimmy23013 points out in the comments, even the parentheses may be unnecessary.

The Bash Reference Manual shows that functions can be defined as follows:

name () compound-command [ redirections ]

or

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

A compound command can be:

That means all of the following are valid:

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

And I've been using curly brackets like a sucker...

A shorter syntax for infinite loops (which can be escaped with break or exit statements) is

for((;;)){ code;}

This is shorter than while true; and while :;.

If you don't need break (with exit as the only way to escape), you can use a recursive function instead.

f(){ code;f;};f

If you do need break, but you don't need exit and you don't need to carry over any variable modification outside the loop, you can use a recursive function with parentheses around the body, which run the function body in a subshell.

f()(code;f);f

Alternatives to head

line is three bytes shorter than head -1, but is being deprecated.

sed q is two bytes shorter than head -1.

sed 9q is one byte shorter than head -9.

Use arithmetic (( ... )) for conditions

You could replace:

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

by

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

(Note: There is no space after if)

or even

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

... or if only one command

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

Further: Hide variable setting in arithmetic construct:

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

or same

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

... where if i > 5, then c = 1 (not 0;)

Use tail recursion to make loops shorter:

These are equivalent in behavior (though probably not in memory/PID usage):

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

And these are roughly equivalent:

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

(technically the last three will always execute the body at least once)

Using $0 requires your script to be in a file, not pasted into the bash prompt.

Eventually your stack might overflow, but you save some bytes.

Quotes can be omitted when printing strings.

echo "example"
echo example

Output in SM-T335 LTE, Android 5.1.1:

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

Use pwd instead of echo to generate a line of output

Need to put a line on stdout but don't care about the contents, and want to restrict your answer to shell builtins? pwd is a byte shorter than echo.

Expand away the tests

Essentially, the shell is a kind of macro language, or at least a hybrid or some kind. Every command-line can be basically broken into two parts: the parsing/input part and the expansion/output part.

The first part is what most people focus on because it's the most simple: you see what you get. The second part is what many avoid ever even trying to understand very well and is why people say things like eval is evil and always quote your expansions - people want the result of the first part to equal the first. That's ok - but it leads to unnecessarily long code branches and tons of extraneous testing.

Expansions are self-testing. The ${param[[:]#%+-=?]word} forms are more than enough to validate the contents of a parameter, are nestable, and are all based around evaluating for NUL - which is what most people expect of tests anyway. + can be especially handy in 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

...while read pulls in not blank lines "${r:+set}" expands to "set" and the positionals get $r appended. But when a blank line is read, $r is empty and "${r:+set}" expands to "" - which is an invalid command. But because the command-line is expanded before the "" null command is searched, "${r:=$*}" takes the values of all of the positionals concatenated on the first byte in $IFS as well. r() could be called again in |{ compound command ;} w/ a different value for $IFS to get the next input paragraph as well, since it is illegal for a shell's read to buffer beyond the next \newline in input.

Use if to group commands

Compared to this tip which removes the if at all, this should only work better in some very rare cases, such as when you need the return values from the if.

If you have a command group which ends with a if, like these:

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

You can wrap the commands before if in the condition instead:

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

Or if your function ends with a if:

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

You can remove the braces:

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

If you need to pass the content of a variable to STDIN of the next process in a pipeline, it is common to echo the variable into a pipeline. But you can achieve the same thing with a <<< bash here string:

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

Element 0 of an array may be accessed with the variable name only, a five byte saving over explicitly specifying an index of 0:

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

split has another (deprecated, but nobody cares) syntax for splitting input into sections of N lines each: instead of split -lN you can use split -N e.g. split -9.

Avoid $( ...command... ), there is an alternative which saves one char and does the same thing:

` ...command... `

Use a pipe to the : command instead of /dev/null. The : built-in will eat all its input.

Use [ instead of [[ and test when possible

Example:

[ -n $x ]


Use = instead of == for comparison

Example:

[ $x = y ]

Note that you must have spaces around the equals sign or else it won't work. Same applies to == based on my tests.

Instead of grep -E, grep -F, grep -r, use egrep, fgrep, rgrep, saving two chars. The shorter ones are deprecated but work fine.

(You did ask for one tip per answer!)

: is a command that does nothing, its exit status always succeeds, so it can be used instead of true.

For arithmetic expansion use $[…] instead of $((…)):

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

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

In arithmetic expansions don't 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

Arithmetic expansion is performed on indexed array subscripts, so don't use $ neither there:

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

In arithmetic expansions don't 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