Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2177
  • Last Modified:

Complicated alias breaks piping its output with "Invalid null command." error

(uname -a : Linux login14 2.6.9-89.0.18.ELsmp #1 SMP Wed Nov 25 06:15:13 EST 2009 x86_64 x86_64 x86_64 GNU/Linux)

I have reduced the actual problem I came across to the minimal set that demonstrates the issue, hence reasons for this approach will not be clear, but are required.

I have two C Shell (tcsh specifically) aliases defined as follows:
alias test_alias1 'echo `echo one \!*`;echo done'
alias test_alias2 'echo `echo one \!*`;echo done;'

Open in new window

The only difference between them is a semicolon at the end of the last command in second alias

If I run these without redirection or piping, everything works fine:
> test_alias1 1 2 3
one 1 2 3
done
> test_alias2 1 2 3
one 1 2 3
done

Open in new window

Redirection to files works, too (kind of: "done" does not get redirected, because of where the redirection gets inserted into the alias, but I don't care about redirecting "done"):
> test_alias1 1 2 3 > tempout

done
> test_alias2 1 2 3 > tempout

done

Open in new window

However, trying to pipe breaks for the alias that ends with a semicolon, returning an error:
> test_alias1 1 2 3 | tee tempout
one 1 2 3
done
> test_alias2 1 2 3 | tee tempout
Invalid null command.

Open in new window

Anyone with a good understanding of why this breaks only if there is a semicolon at the end?

BTW, the workaround is to put the entire invocation of the alias in parenthesis before piping:
( test_alias2 1 2 3 ) | tee tempout

Open in new window

0
marcin_kom
Asked:
marcin_kom
  • 3
  • 2
  • 2
  • +1
4 Solutions
 
ahoffmannCommented:
the ; is an optional separator for commands and only required when there is no newline inbetween
hence your final ; will be followed by a command, this is at least what the (tc)shell interpreter expects
as long as there is nothing, the missing "null command" is silently ignored, but when piped the final process has no open STDOUT to be bound to its STDIN
see in  man tcsh: "Simple commands, pipelines and sequences"

finally: your trailing ; is useless and should be removed
0
 
Gerwin Jansen, EE MVETopic Advisor Commented:
test_alias1 evaluates to:

echo 1 2 3 ; echo done | tee test.txt > tempout

tee attaches to the output of "echo done" so on screen you will see 1 2 3 and done - tempout will contain done

test_alias2 evaluates to:

echo 1 2 3 ; echo done; | tee test.txt > tempout

again, tee attaches to the output of "echo done; " but there is no command given after the ; so an attempt is made to pipe the output of a none existing command - this fails

the ( ... ) construction is working because the combined output of test_alias2 is what tee is attaching to

other shells give errors as well btw, like bash for example:

$echo ; | more
bash: syntax error near unexpected token `|'
$ echo  | more

$
0
 
Garry GlendownConsulting and Network/Security SpecialistCommented:
This works for me:

alias tst '( echo `echo one \!*`; echo done)'
alias tst2 '( echo `echo one \!*`; echo done;)'

Open in new window


/root# tst2 1 2 3 | tee aaaa
one 1 2 3
done
/root# cat aaaa
one 1 2 3
done

Open in new window


As already mentioned, the trailing ";" is superfluous ...
0
Visualize your virtual and backup environments

Create well-organized and polished visualizations of your virtual and backup environments when planning VMware vSphere, Microsoft Hyper-V or Veeam deployments. It helps you to gain better visibility and valuable business insights.

 
Gerwin Jansen, EE MVETopic Advisor Commented:
@Garry-G - but of course, you just wrote the already written workaround by the asker :-) The issue is the empty command that cannot be redirected to the pipe
0
 
Garry GlendownConsulting and Network/Security SpecialistCommented:
Marcin suggested putting the "()" around the command line calling the alias, while I put it INSIDE the alias, removing the need for putting it in the command line ... not quite the same, is it?
0
 
Gerwin Jansen, EE MVETopic Advisor Commented:
@Garry-G - As far as I understand, the asker is looking for an explanation - just removing the ; already fixes the issue :D - but feel free to make additional suggestions...
0
 
marcin_komAuthor Commented:
Hello All,

Thank you for all of the responses and idea.  Let me provide some clarifications/responses here.

Unquestionably, the ";" is superfluous, but it is a byproduct of the way a vendor's script "builds" an alias.  Specifically, the script has a bunch of conditionals, storing either an empty string or "command;" into components $partA, $partB, etc.  The alias is then defined as "cmd;$partA$partB"...  I think there are cleaner ways of doing this but the setup script is what it is.

ahoffmann,

Your explanation makes sense.  The pipeline "|" joins two adjacent simple commands, thus gets attached to an 'empty' command when the alias ends in a semicolon.

My confusion came from the fact that redirecting to a file worked, but this is because the shell considers redirection as an argument, hence the alias arguments expansion "!*" ends up 'moving' the redirection from the end of command to where "!*" appears.


gerwinjansen,

You are pointing to the correct issue, but effectively showing ahoffmann's suggestion from another angle, although your 'evaluation' of the expression is not totally accurate based on how test_alias1 and test_alias2 are defined.

Garry-G,

gerwinjansen is correct that you presented a modified version of my solution.  The challange is that I don't have control over the definition of the alias, hance can't put the parenthesis around it.

It did, however, make me think of a way to 'redefine' the existing alias, with the following command:
alias alias_name '('`alias alias_name`')'

Open in new window

This 'corrects' the alias.

Thanks everyone!
0
 
marcin_komAuthor Commented:
My last comment provides a command that 'fixes' an existing alias.  Assigned 0 points to own answer.
0

Featured Post

Prep for the ITIL® Foundation Certification Exam

December’s Course of the Month is now available! Enroll to learn ITIL® Foundation best practices for delivering IT services effectively and efficiently.

  • 3
  • 2
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now