1

I recently saw the following line:

curl -fsSL https://deb.nodesource.com/setup_17.x | bash - 

What is the difference between bash and bash -? I tried running both variants, and they seem to do the same thing.

man bash didn't supply an answer either.

Foobar
  • 7,458
  • 16
  • 81
  • 161
  • 1
    @jhnc Thank you for the correction, I will delete my misleading comments. And thank you for addressing GenoChen's and my misunderstanding explicitly in your answer. – joanis Oct 09 '22 at 16:21
  • @triplee that is a very poor choice of duplicate, since none of the answers there discuss the use of the dash to end a list of command line parameters (which I had never seen before - is it unique to bash?). Voting to reopen. – joanis Oct 09 '22 at 16:30
  • @joanis My bad, you're right. For the record, the duplicate was about the general convention to let `-` as a file name argument mean, read standard input. – tripleee Oct 09 '22 at 18:26
  • @joanis see my answer edit. Apparently POSIX include single dash use in shell invocation as an equivalent to `--`, for compatibility with the way that single dash had been used historically. – jhnc Oct 09 '22 at 22:13
  • @jhnc nice digging, and I guess it makes sense in that old context. Thanks for the edit! – joanis Oct 10 '22 at 13:36

1 Answers1

4

The commands are identical.

The author probably believes that passing - as an argument will make bash read commands from stdin but bash will do that anyway.

In fact, the bash man-page explains that - is equivalent to -- and terminates option processing:

--    A  --  signals the end of options and disables further option
      processing.  Any arguments after the -- are treated as  file‐
      names and arguments.  An argument of - is equivalent to --.

Note that if there was something after the -, then behaviour might be different. For example:

$ echo "echo foo" > ./-c
$ chmod +x ./-c
$ export PATH=.:"$PATH"
$ bash   -c "echo bar"
bar
$ bash - -c "echo bar"
foo
$

Note also, it is not the case that using bash - makes it a login shell. This can be demonstrated by adding something printable to ~/.bash_profile:

$ export HOME=$(mktemp -d)
$ cd
$ echo "echo login shell" > .bash_profile
$ echo "echo hello" | bash
hello
$ echo "echo hello" | bash -
hello
$ echo "echo hello" | bash -l
login shell
hello
$

The meaning in the manpage of "A login shell is one whose first character of argument zero is a -" is that the command name starts with a hyphen:

$ cat .bash_profile
echo login shell
$ ln -s /bin/bash ./notLoginShell
$ ln -s /bin/bash ./-isLoginShell
$ export PATH=~:"$PATH"
$ echo "echo hello" | notLoginShell
hello
$ echo "echo hello" | -isLoginShell
login shell
hello
$

Addendum

Using bash - may be a cargo-culted carry-over from a technique used historically to prevent a particular type of security exploit.

POSIX comments:

On systems that support set-user-ID scripts, a historical trapdoor has been to link a script to the name -i. When it is called by a sequence such as:

sh -

or by:

#! usr/bin/sh -

the historical systems have assumed that no option letters follow. Thus, this volume of POSIX.1-2017 allows the single <hyphen-minus> to mark the end of the options, in addition to the use of the regular "--" argument, because it was considered that the older practice was so pervasive.

unix-faq explains:

suppose the script is called /etc/setuid_script, starting with:

#!/bin/sh

Now let us see what happens if we issue the following commands:

$ cd /tmp
$ ln /etc/setuid_script -i
$ PATH=.
$ -i

We know the last command will be rearranged to:

/bin/sh -i

But this command will give us an interactive shell, setuid to the owner of the script!

Fortunately this security hole can easily be closed by making the first line:

#!/bin/sh -

The - signals the end of the option list: the next argument -i will be taken as the name of the file to read commands from, just like it should!

jhnc
  • 11,310
  • 1
  • 9
  • 26