In Bash, Why 'X=100 Echo $X' Doesn't Print Anything

In Bash, why `x=100 echo $x` doesn't print anything?

The $x is expanded before echo runs, and the result is passed to echo as an argument. echo does not use the value of x in its environment.

In the first example, read uses the value of IFS in its environment to split the string it receives via the here string.

echo -e doesn't print anything

This is a tough one ;)

Usually you would use double dashes to tell the command that it should stop interpreting options, but echo will only output those:

$ echo -- -e
-- -e

You can use -e itself to get around the problem:

$ echo -e '\055e'
-e

Also, as others have pointed out, if you don't insist on using the bash builtin echo, your /bin/echo binary might be the GNU version of the tool (check the man page) and thus understand the POSIXLY_CORRECT environment variable:

$ POSIXLY_CORRECT=1 /bin/echo -e
-e

I just assigned a variable, but echo $variable shows something else

In all of the cases above, the variable is correctly set, but not correctly read! The right way is to use double quotes when referencing:

echo "$var"

This gives the expected value in all the examples given. Always quote variable references!


Why?

When a variable is unquoted, it will:

  1. Undergo field splitting where the value is split into multiple words on whitespace (by default):

    Before: /* Foobar is free software */

    After: /*, Foobar, is, free, software, */

  2. Each of these words will undergo pathname expansion, where patterns are expanded into matching files:

    Before: /*

    After: /bin, /boot, /dev, /etc, /home, ...

  3. Finally, all the arguments are passed to echo, which writes them out separated by single spaces, giving

    /bin /boot /dev /etc /home Foobar is free software Desktop/ Downloads/

    instead of the variable's value.

When the variable is quoted it will:

  1. Be substituted for its value.
  2. There is no step 2.

This is why you should always quote all variable references, unless you specifically require word splitting and pathname expansion. Tools like shellcheck are there to help, and will warn about missing quotes in all the cases above.

bash: print x number of blank lines

As Jerry commented you made a syntax error.

This seems to work :

for i in {1..100}
do
echo "\n"
done

Echo newline in Bash prints literal \n

Use printf instead:

printf "hello\nworld\n"

printf behaves more consistently across different environments than echo.

Bash variable not decrementing in a pipeline

It does decrement if you don't use a pipeline (and avoid a sub shell forking):

x=10

f() {
if ((x)); then
echo $((x--))
f
fi
}

Then call it as:

f

it will print:

10
9
8
7
6
5
4
3
2
1

Since decrement is happening inside the subshell hence current shell doesn't see the decremented value of x and goes in infinite recursion.


EDIT: You can try this work around:

x=10

f() {
if ((x)); then
x=$(tr 0-9 A-J <<< $x >&2; echo $((--x)))
f
fi
}

f

To get this output:

BA
J
I
H
G
F
E
D
C
B

Why can't I specify an environment variable and echo it in the same command line?

What you see is the expected behaviour. The trouble is that the parent shell evaluates $SOMEVAR on the command line before it invokes the command with the modified environment. You need to get the evaluation of $SOMEVAR deferred until after the environment is set.

Your immediate options include:

  1. SOMEVAR=BBB eval echo zzz '$SOMEVAR' zzz.
  2. SOMEVAR=BBB sh -c 'echo zzz $SOMEVAR zzz'.

Both these use single quotes to prevent the parent shell from evaluating $SOMEVAR; it is only evaluated after it is set in the environment (temporarily, for the duration of the single command).

Another option is to use the sub-shell notation (as also suggested by Marcus Kuhn in his answer):

(SOMEVAR=BBB; echo zzz $SOMEVAR zzz)

The variable is set only in the sub-shell

echo that outputs to stderr

You could do this, which facilitates reading:

>&2 echo "error"

>&2 copies file descriptor #2 to file descriptor #1. Therefore, after this redirection is performed, both file descriptors will refer to the same file: the one file descriptor #2 was originally referring to. For more information see the Bash Hackers Illustrated Redirection Tutorial.



Related Topics



Leave a reply



Submit