10

Up to now I thought that a semicolon in the shell has (somehow) the same meaning as a line break. So I was surprised that for

alias <name>=<replacement text>; <name>

<name> is unknown while it is known in the next line. csh, tcsh, sh, ksh and bash behave the same. At least for csh it does not matter if alias is used directly or if a script is sourced before the semccolon--the aliases are not known after ; but the are known in the next command line. Is this a bug or is this behavior intended?

cuonglm
  • 153,898
  • 1
    "I thought that a semicolon in the shell has (somehow) the same meaning as a line break" Nearly. Not quite! – Lightness Races in Orbit Nov 02 '15 at 20:10
  • 2
    The interpretation of semicolon and newline depends on how the parser is called. For the "dot" command, the Bourne Shell calls the parser with the "NLFLG" that tells it to treat newline and semicolon equal in some situations, but this is not the case elsewhere. In general, semicolon and linebreak are not equivalent as you can have a linebreak, where a semicolon would cause a syntax error. – schily Nov 03 '15 at 09:08

3 Answers3

10

The alias syntax you are using is inappropriate for a POSIX shell, for a POSIX shell, you need to use:

alias name='replacement'

But for all shells, this cannot work as the alias replacement is done early in the parser.

Before your alias setup is executed, the whole line was read by the parser and for this reason, your command line wil not work.

If the alias appears on the next command line, it will work.

schily
  • 19,173
  • In addition, some shells like yash or zsh would not expand the alias in shell -c 'alias name=replacement<newline>replacement'. For AT&T ksh, you'd have the problem with sourced scripts. – Stéphane Chazelas Nov 02 '15 at 13:46
  • I need to use the csh in this case--there no = is used in the alias syntax. – user3224237 Nov 02 '15 at 13:52
  • @user3224237 - this has nothing to do with the =. it is because the alias expansion happens when the shell first sees the line, which is before you define the alias. – cas Nov 02 '15 at 23:24
  • @Stéphane Chazelas The behavior with "sourced" scripts is caused by the fact that the Bourne shell completely parses such files before they are execured. Ksh is based on the Bourne Shell source and everything that was not changed behaves the same. – schily Nov 03 '15 at 08:55
  • @schily, yes, it's the same reason for zsh/yash -c 'code' where code is parsed as a whole. It doesn't seem to be the case for the Bourne shell. So I suppose the Bourne shell parses that code there one line at a time. – Stéphane Chazelas Nov 03 '15 at 09:04
  • See my other comment...on the question – schily Nov 03 '15 at 09:10
6

This behavior is intended and specified by POSIX under Alias Substitution.

An alias was substituted right after the shell perform Token Recognition and before any Grammar Rules applied. At the time you called the alias <name>, the command alias wasn't executed.

cuonglm
  • 153,898
0

If you really want one-liner, then you can use function instead of alias.

E.g. you make py3 alias, but it only works in second line:

$ alias py3=python3; py3 -c 'print("hello, world")'

Command 'py3' not found, did you mean:

  command 'py' from deb pythonpy
  command 'hy3' from deb python3-hy
  command 'pyp' from deb pyp

Try: sudo apt install <deb name>

$ py3 -c 'print("hello, world")'
hello, world

You can define py3 as function instead of alias:

$ function py3() { python3 "$@"; }; py3 -c 'print("hello, world")'
hello, world

Or export -f before used in child process later:

$ function py3() { python3 "$@"; }; export -f py3; bash -c "py3 -c 'print("'"hello, world"'")'"
hello, world

And if you be aware the difference of variable vs alias/function, then you can use variable too:

$ py3='python3'; $py3 -c 'print("hello, world")'
hello, world

and no need export -f:

$ py3='python3'; bash -c "$py3 -c 'print("'"hello, world"'")'"
hello, world
林果皞
  • 5,156
  • 3
  • 33
  • 46