Ksh: run commands from pipe

I create commands within a pipe and finally want them to be executed instead of being displayed on the screen. What is the last stage in this pipe? I found by guessing that "ksh" is working, but is this the best to use here?

It boils down to this:

 echo "print Hello World!"| ksh

What is the "best" command at the end of the pipe to execute the commands that come down the pipe?

Try this instead of pipe

echo 'print Hello World' >/dev/null  2>&1

meaning redirect both output and errors to /dev/null

??? ... that's not what I asked for. Was I that unclear?

Hello Akshay Hegde/Cochise,

There is no meaning for using >/dev/null 2>&1 in case of echo . We can use this command if we are running any script and we want to see output if that script is storing it in any output file, also it will avoid errors too while execution of script too. There this command can be useful.

./script.ksh >/dev/null 2>&1

Thanks,
R. Singh

I am sorry, what kind of commands you are creating ? its bit unclear to me, whether you are trying to create commands which can be executed on shell ? is so you are on right path you can ksh, sh etc.

ksh is "best" if you want to use ksh.
sh is "best" if you want to use sh.
zsh is "best" if you want to use zsh.

etc.

But why bother? Why not just run the command, instead of printing it? Shell-within-shell or eval bruteforcing usually means something else was forgotten along the way.

For better understanding of my problem, here is the long story:

I have a large log file, that has some lines like this:

skipping: /usr/bin/chuser "gecos=ipsec;MDE0M819;;F" ipsec (TESTMODE)
skipping: /usr/bin/chuser "gecos=nobody;MDE0M819;;F" nobody (TESTMODE)
skipping: /usr/bin/chuser "gecos=perfmgr;MDE0M819;;F" perfmgr (TESTMODE)

The lines may occur multiple times.

I want to find these lines, remove duplicates, strip off "skipping:" and "(TESTMODE)" and then execute the remainining chuser command.

What I have built is this:

grep 'chuser "gecos=' modify.LOG|sort|uniq|sed 's/skipping: //; s/ (TESTMODE)//'|ksh

This works and is what I asked for.

New question: I would like to have the command string displayed on the terminal before it is send to ksh for execution.
Is there a smarter and shorter way than doing it in a do loop like below?

grep 'chuser "gecos=' modify.LOG|sort|uniq|sed 's/skipping: //; s/ (TESTMODE)//'|while read line;do print - $line;ksh "$line";done

Not sure if I understood your requirements correctly, but this should do the job:

sed -nr '/chuser \"gecos=/ s/skipping: |\(TESTMODE\)//gp' modify.LOG | sort -u | tee /dev/tty | sh

You could use ksh or bash as well to execute the commands. Supplying it the -x option would eliminate the need for the tee step.

2 Likes

/dev/tty can become problematic.
Also I have seen bugs with ksh -x so I recommend

... | ksh -v

For lines that simple -- no evaluation, natural splitting on spaces -- I don't think you need to feed it into sh. The shell's own natural splitting should take care of it once you have it.

# VAR="echo asdf;qwerty something else"
# $VAR
asdf;qwerty something else

#

Thank you. Brilliant solution, unfortunately sed in ksh does not know the -r option. How could that sed command look instead? I'm trying now quite a while without success.

Has nothing to do with ksh, it's the version of sed on your system.

My try at it:

awk '{ gsub(/(^skipping: )|( ipsec \(TESTMODE\))|"/, ""); } 1' inputfile | while read LINE
do
        # Remove the 'echo' once you've tested and found it does what you ant.
        echo $LINE
done

Use nawk on Solaris.

In principle you can use any process which output are code-lines and pipe that in ksh (or any other shell i know, for that matter):

typeset -i iCnt=0

while [ $iCnt -le 10 ] ; do
     print - "echo foo $iCnt bar"
     (( iCnt += 1 ))
done | ksh

Notice, however, that there are certain things to be aware of:

First, your lines have to observe the line-length limit the system is compiled with. This is always the case but when writing lines of code you notice extraordinary long lines more easily than when you generate them.

typeset -i iCnt=0

var="echo "
while [ $iCnt -le <some-big-number> ] ; do
     var="$var $iCnt"
     (( iCnt += 1 ))
done
print - $var | ksh

This will eventually break for either the line " var="$var $iCnt " being too long, the number of maximum arguments being exceeded or the maximum commandline length being exceeded. Which of these events will happen first and at which value of some-big-number depends on your system, the version, etc..

Another possible problem is possible multiple interpretations of your commandline by a shell. Consider a try to execute a command on several selected hosts:

sed '.....' /some/raw/listofhosts |\
while read chHost ; do
     print - "ssh user@$chHost /some/command"
done | ksh

In this form it would work, because the commandline will not change with several shells interpreting it, but how about a command which should receive several parameters, some of them containing spaces:

ssh user@host /some/command "first arg" "second arg"

This will work on the commandline, but in your script-constructing script you would have to do:

sed '.....' /some/raw/listofhosts |\
while read chHost ; do
     print - "ssh user@$chHost /some/command \"first arg\" \"second arg\""
done | ksh

I hope this helps.

bakunin

1 Like

Try

sed -n '/chuser \"gecos=/ s/skipping: \|(TESTMODE)//gp' modify.LOG | sort -u | sh -vx

\| is GNU sed.
Standard sed is either

sed -n '/chuser \"gecos=/{s/^ *skipping: //;s/ (TESTMODE) *$//;p;}' modify.LOG | sort -u | ksh -v

or

sed '/chuser \"gecos=/!d;s/^ *skipping: //;s/ (TESTMODE) *$//' modify.LOG | sort -u | ksh -v
1 Like

Thanks to bakunin for his interesting lecture on piping commands to ksh.

And thanks to MadeInGermany for converting the sed command to non-GNU syntax.
I love short and straight forward code solutions. :b:
I will surely save these two sed lines to my examples file.