0

This uses "process substitution" (<()) and a "heredoc" (cat << EOF...EOF) to open a new bash process where it runs the startup "file" (--rcfile) containing alias foo="echo hey you. Here is the command:

bash --rcfile <(
cat << EOF
alias foo="echo hey you"
EOF
)

It works on Ubuntu just fine, as you can see here:

$ bash --rcfile <(
> cat << EOF
> alias foo="echo hey you"
> EOF
> )
$ foo
hey you
$ alias
alias foo='echo hey you'

However, when I try to run this on certain embedded Linux devices, I get the following error. Why? How do I make it run there too?

-sh: syntax error: unexpected "("

Full output:

$ bash --rcfile <(
-sh: syntax error: unexpected "("
$ cat << EOF
> alias foo="echo hey you"
> EOF
alias foo="echo hey you"
$ )
-sh: syntax error: unexpected ")"

In case this helps, here are my which bash and bash --version outputs on Ubuntu vs the embedded Linux device:

# 1. Ubuntu

$ which bash
/bin/bash
$ bash --version
GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.


# 2. Embedded Linux device

$ which bash
/bin/bash
$ bash --version
GNU bash, version 5.0.16(1)-release (aarch64-buildroot-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Not a duplicate:

This is related but does not seem to be a duplicate: dash reports 'Syntax error: "(" unexpected' when using process substitution.

Related:

  1. [my own question] https://stackoverflow.com/questions/69891328/what-is-the-syntax-in-shell-bash-and-how-do-i-search-for-it

Notes to self

My end-goal is to automatically create some custom aliases when I ssh in, like this perhaps:

ssh -t username@ip_address '/bin/bash --rcfile <(
cat << EOF
alias foo="echo hey you"
EOF
)'

Update: done! Here is what I came up with:

# Store your password into a file
echo "my_password" > ~/pw

# Manually add something like this to your ~/.bash_aliases (recommended) or ~/.bashrc file on the PC
# you are ssh-ing FROM:
alias gs_ssh="sshpass -f ~/pw scp /etc/skel/.bashrc [email protected]:/tmp \
&& sshpass -f ~/pw ssh -t -o 'ServerAliveInterval 60' [email protected] 'bash --rcfile /tmp/.bashrc'"

See my repo here: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/tree/master/home/.ssh#optional-but-recommended-alias.

Gabriel Staples
  • 2,192
  • 1
  • 24
  • 31
  • You have a device with bash, sure, but are you running this command in bash? – muru Nov 09 '21 at 00:42
  • @muru, I'm typing `bash --rcfile...`, so it is running it in `bash` right there, no? The `--rcfile` part and everything thereafter are the parameters to the `bash` cmd. – Gabriel Staples Nov 09 '21 at 00:45
  • 2
    Depends on what shell you're typing `bash --rcfile` into. That's the one that interprets the `<(...)` – muru Nov 09 '21 at 00:47
  • @muru: aaaah; that makes sense! That's running in `sh` I think. So, first I must run `bash` and THEN I can run that next cmd with the process substitution. – Gabriel Staples Nov 09 '21 at 00:48
  • @muru, okay: manually running `bash` first allows me to then run the cmd fine on the Linux device. BUT, I cannot seem to script the two cmds together as the first shell is what always interprets both of them. So, I'm still stuck. – Gabriel Staples Nov 09 '21 at 00:52
  • Note: running [`echo $0`](https://askubuntu.com/a/590902/327339) on the embedded Linux device shows `-sh`, meaning it is running `sh` by default when I first log in. – Gabriel Staples Nov 09 '21 at 00:54

2 Answers2

2

Do the embedded Linux devices support /dev/fd/ entries? If they do, try passing the initialization commands over file descriptor #3, like this:

bash --rcfile /dev/fd/3 3<<EOF
alias foo="echo hey you"
exec 3<&-
EOF

EDIT: Stéphane Chazelas suggested adding exec 3<&- as the final command in the "script"; this closes the file descriptor, so it's not left dangling for the entire shell session.

Gordon Davisson
  • 4,360
  • 1
  • 18
  • 17
  • Yes, that works! `ls /dev/fd` shows: `0 1 2 3 4`. What does all these mean? Why did you choose `3` instead of one of the other four options? See also my follow-up question here: [What does the output of `ll /proc/self/fd/` (from `ll /dev/fd`) mean?](https://unix.stackexchange.com/questions/676683/what-does-the-output-of-ll-proc-self-fd-from-ll-dev-fd-mean) – Gabriel Staples Nov 09 '21 at 02:09
  • Note to self: see also: [What is the portable (POSIX) way to achieve process substitution?](https://unix.stackexchange.com/a/309594/114401) – Gabriel Staples Nov 09 '21 at 02:14
  • 1
    @GabrielStaples File descriptors #0 through #2 are already in use (#0 is standard input, #1 is standard output, #2 is standard error), but #3 is almost always available for random other uses. – Gordon Davisson Nov 09 '21 at 02:20
  • That makes sense; thank you very much. I'm beginning to make better sense of Linux. When we open a new file with [`open()`](https://man7.org/linux/man-pages/man2/open.2.html), and it returns a file descriptor integer to us, does that mean `/dev/fd` will now show another file descriptor integer greater than `4`? – Gabriel Staples Nov 09 '21 at 02:23
  • 1
    @GabrielStaples I think so, but I'm not fully familiar with the details (and it may depend on the OS). – Gordon Davisson Nov 09 '21 at 02:24
  • 1
    You could also add a `exec 3<&-` at the end of that heredoc for the tempfile or pipe used for the here doc to be released after bash has read it. – Stéphane Chazelas Nov 09 '21 at 06:39
2

Whether or not the syntax of your command is supported or not is determined by whatever shell you are currently running.

Your current shell is sh when you try to execute your bash --rcfile <(...) command, which is evident from the error message where the shell identifies itself as a sh shell running as a login shell. This shell does not generally understand process substitutions.

One way to work around this is to first exec bash, which is replacing the current shell with a shell that understands process substitutions, or to do as is suggested by Gordon Davisson and provide the temporary initialization file via an alternative file descriptor.

exec bash

bash --rcfile <( cat <<'BASHRC'
alias foo='echo bumblebee'
BASHRC
)
bash --rcfile /dev/fd/3 3<<'BASHRC'
alias foo='echo bumblebee'
exec 3<&-
BASHRC

Note that you, in either case, most likely want to quote the here-document, unless you need the current shell to carry out expansions in the document before the new bash shell reads it. You may also want to use exec bash if replacing the current shell completely is what you want to do.

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • Ideally, the first example would work as a single command, but it does not. Rather, `exec bash` (or just `bash`) must be run first, and then after running that I can copy/paste the next part of the command and it works with process substitution. It looks like I cannot script the whole thing as a single command while having the `bash` part run first. – Gabriel Staples Nov 09 '21 at 16:36
  • How is `exec bash` different from `bash` anyway? Both seem to work the same in testing. – Gabriel Staples Nov 09 '21 at 16:37
  • 1
    @GabrielStaples If you give the command `bash`, you start a `bash` shell session. If you then say `exit` in that session, you get back to the initial shell. With `exec bash`, you _replace_ the current shell with a `bash` shell session, which means that if you type `exit`, you terminate that terminal session completely (or log out, if were logged in via a text console or SSH). – Kusalananda Nov 09 '21 at 17:16
  • Ahhh, I actually noticed that when I typed `exit` a few minutes ago but didn't understand the new and "aberrant" behavior, nor why it happened! – Gabriel Staples Nov 09 '21 at 17:19