3

I am using a scrtipt with instruction 'SH -c command', where command is an alias from bash, this alias can not be interpreted into Bourne shell. ¿Do you have any idea for set this alias into Bourne shell and getting that it works in the new shell? Thanks everyone !

  • 1
    The new shell does not have an alias defined in the current shell, otherwise aliases would make things extremely confusing. Aliases are meant for interactive use not for scripting. Make a procedure instead of an alias, call it to produce the desired command (without aliases) and only then pass to a second shell. – grochmal Aug 11 '16 at 15:36
  • 1
    As a minor thing, commands in Unix-like systems are usually case-sensitive, so you're likely not running SH, but sh. – ilkkachu Aug 11 '16 at 15:58

2 Answers2

4

I would be surprised if it's a real Bourne shell you have on Linux. Though the Bourne shell has now been ported to Linux, it's generally not installed or even packaged by default.

You'd only install it for archaeology purposes.

Maybe you're confusing sh (which nowadays refers to an interpreter or another of the POSIX sh language) with the Bourne shell (an ancient shell that also used to be called sh (and from which modern shs descend, but also differ)).

The Bourne shell didn't have aliases. Modern sh do.

Aliases however are local to the current shell. If you execute a new shell (whether it's bash, sh, csh, zsh...), that new shell will not inherit those aliases.

You'd need to redefine those aliases in the new shell.

bash has a way to dump the definition of one of its alias in a syntax that is compatible with that of sh. So you could do:

alias foo='echo foo' # alias defined in bash
foo_definition=$(alias foo)
sh -c "$foo_definition
foo"

Or simply:

sh -c "$(alias foo)
foo"

Now, there's a catch in that it doesn't work in all implementations of sh. First you'll noticed we didn't do:

sh -c "$(alias foo);foo"

Which would have worked in no sh implementation.

That's because aliases are really like some form of macro expansion. Because alias expansion is done prior to parsing, in alias foo='echo foo'; foo, by the time the alias command is run, the line has already been parsed.

Putting the alias definition on one line and its usage on the next works around that for some shells, but some others (like yash or zsh) parse the whole sh -c code as a whole, so alias expansion won't work there.

However because aliases are more or less macros, that is the substitution of some text with some other text, you might as well do the substitution by hand.

You can get the value of an alias by doing:

eval "$(alias foo | sed '1s/ /_/')"

Which would store the definition of the foo alias into the $alias_foo variable.

Then, you can do:

sh -c "$alias_foo"

To have the value of the foo alias passed as shell code to sh.

You may prefer using functions than aliases for that purpose. Like for aliases, functions are local to the current shell. Some shells like rc or bash can export functions to other invocations of the same interpreter.

foo() { echo foo; }
export -f foo
sh -c foo

Would only work on systems where sh is implemented with bash (mostly only Apple OS/X and some Linux-based systems).

A more portable approach would be like for aliases to dump the definition of the function into the code passed to sh -c:

sh -c "$(typeset -f foo); foo"

This time, no problem with time-of-expansion, time-of-parsing as functions as opposed to aliases as functions are real structures of the language.

However, you need to make sure the definition of the function contains code that is valid sh syntax and doesn't use any bash extension.

1

Speaking about Bash in particular-

That happens because when Bash is given a command using -c, it starts in non-interactive mode, and in particular, alias expansion is disabled.

In general, you shouldn't use aliases in scripts, but instead you should use shell functions or other scripts. If you really want to use aliases, try bash -ic <alias_command>. The -i will start the shell in interactive mode, read your configuration files such as /.bashrc, then alias expansion will be enabled.

Note- Aliases that Bash sees will come from the configuration files, not from the parent shell.

  • 1
    Alias expansion is done in sh -c. It's only in bash (when not called as sh) that aliases are not expanded when the shell is not interactive. – Stéphane Chazelas Aug 11 '16 at 16:18
  • <shell> -ic <alias_command> will not cause the aliases to be magically passed to the new <shell>. However, with some shells, that will cause the ~/.bashrc/.zshrc to be sourced and then the alias definitions in there being loaded. – Stéphane Chazelas Aug 11 '16 at 16:20
  • Thanks, I edited to talk about bash only. – Matei David Aug 11 '16 at 16:27