# How to know, when to use 1> and 2>



## Seeker (Jan 28, 2010)

In cron I've put line:

```
echo "HEEEELOOO!!" && portsnap fetch update > /dev/null && echo "HEEEELOOO!!"
```

So, what I wanted to achieve:
If all went without errors, then don't pester me with STDOUT output emails
That is..., IF error occurs with portsnap, THEN email me STDERR.

And here we come to unlogic behaviour.
Line above, in cron will fail and only first echo "HEEEELOOO!!" will appear in mail as fail occur at second(portsnap) part
But I get no reason/explanation, becuse STDERR is empty and portsnap's error msg ended up in STDOUT, which I've set to go to hell(/dev/null), assuming it would contain repetitive pestering content

Removing _' > /dev/null'_, part exposed:


> portsnap fetch should not be run non-interactively.
> Run portsnap cron instead.



Now THAT was supposed to go in STDERR!


Soon I will start to code scripts that control OS, so I need to know, this.
ATM, look very unlogic to me.


----------



## aragon (Jan 28, 2010)

It really depends on the app.  If it is coded to output a message to stdout, it will output there.  If it is coded to output to stderr, it will output there.

portsnap was coded to output that message to stdout.  I don't know of a design standard that defines when/where the two should be used that is well followed by programmers.

In other words, YMMV.


----------



## Seeker (Jan 28, 2010)

You got to be kidding me right?!?
Well then, *that is a CHAOS*...
And we want *order*!

I mean..., this totally defeats the purpose of existance of both STDOUT and STDERR.
Then we should just replace them with "1 out"


----------



## aragon (Jan 28, 2010)

Seeker said:
			
		

> I mean..., this totally defeats the purpose of existance of both STDOUT and STDERR.
> Then we should just replace them with "1 out"


Well, you could try contact the portsnap author.  Go ahead and submit a patch against portsnap.  It's a dead simple fix.  Lines 1002-1005 in /usr/src/usr.sbin/portsnap/portsnap/portsnap.sh.


----------



## SirDice (Jan 28, 2010)

I have to agree, errors should be printed to stderr not stdout. It's probably relatively easy to modify portsnap to do this.

To fix this issue you could just write a wrapper script that runs portsnap and checks it's return code.


----------



## expl (Jan 28, 2010)

You should handle stdout and stderr both as possible outputs for error. Pipe stderr to stdout, then handle return value of executed program (like portsnap) if program returned other than 0 then process stdout as error description or/and handle return value via perror(1).


----------



## Seeker (Jan 28, 2010)

I am talking about *global* scope, of this issue, that is active for ALL application.
No mater are they from base system, as portsnap is(!), or from apps, installed from ports.

I can't write patch for all of them.


----------



## expl (Jan 28, 2010)

Yes thats why like I said you should handle both stdout and stderr as possible error output. Generally most of apps handle return values correctly so scripts depending on them rarely fail.


----------



## Graaf_van_Vlaanderen (Jan 28, 2010)

Isn't this the same when starting an application from terminal and warnings and errors are printed to the (Sdtout) terminal?

I always have to start an application with this addition:

in csh:


```
>& /dev/null &
```

in sh:


```
2> /dev/null &
```

Then all the output is gone.


----------



## Seeker (Jan 28, 2010)

Ok, ok, that is *when I start* do scripting.
Right now I use form of, from example in cron:

```
comm[B]A[/B] && comm[B]B[/B] && comm[B]C[/B]
```
One that fails, stops further execution in chain...
And THEN I wana error message

So if I force *2>&1* I can't get rid of _pestering effect_, when all is well


----------



## expl (Jan 28, 2010)

Seeker said:
			
		

> Ok, ok, that is *when I start* do scripting.
> Right now I use form of, from example in cron:
> 
> ```
> ...



Your script should cache output as a log for later reference by your script's procedures or user itself. So you end up with 0 output from running apps in the terminal. And then parse the needed output from the log when needed.


----------



## Seeker (Jan 28, 2010)

expl said:
			
		

> Your script should cache output as a log for later reference by your script's procedures or user itself. So you end up with 0 output from running apps in the terminal. And then parse the needed output from the log when needed.



But then, I won't know *WHEN* is that _*needing time!*_
Simply because in both cases, no matter if error occurs or not, everything goes into logs.

So I am left to the: _"Something doesn't feel right"_ effect..., so let me check logs, maybe I find something useful, _down there._

That sucks!


----------



## expl (Jan 28, 2010)

Return values indicate when you need to check the log. If app executed fine it should return 0, if not it will return something else usually an error code.


----------



## Seeker (Jan 28, 2010)

expl said:
			
		

> Return values indicate when you need to check the log. If app executed fine it should return 0, if not it will return something else usually an error code.


And(_second time_), that is useful, *when I start* do scripting.
Now, this is chained cmd line, in crontab for cron to execute, of type:

```
commA && commB && commC
```


----------



## expl (Jan 28, 2010)

Well there are no easy solutions.


----------



## Seeker (Jan 28, 2010)

expl said:
			
		

> Well there are no easy solutions.


There *are*!
It is just, that those app. devs, are irresponsible cattle(that has to be tamed), thus making this *mess, with no easy solutions!*


----------



## phoenix (Jan 29, 2010)

What everyone is saying is that you should not be writing "appA && appB && appC" directly in the crontab.  Instead, just use /path/to/some/script.  Then write a wrapper script that correctly calls each app, saves their output somewhere, checks their return code, and either outputs nothing (return code is 0) or processes the output (return code is non-0).

Which is pretty much what everyone does.  No one executes more than simple commands directly in crontab.


----------



## aragon (Jan 29, 2010)

Seeker said:
			
		

> There *are*!
> It is just, that those app. devs, are irresponsible cattle(that has to be tamed), thus making this *mess, with no easy solutions!*


There are no guarantees in life.  Anyone older than 12 should know this.

As for a "simple" solution, maybe this is what you're looking for?


```
(commA >/tmp/blah 2>&1 || ( cat /tmp/blah && false) ) && (commB >/tmp/blah 2>&1 || cat /tmp/blah )
```

When I said simple, I actually meant messy as hell.


----------



## Oxyd (Jan 29, 2010)

aragon said:
			
		

> There are no guarantees in life.  Anyone older than 12 should know this.
> 
> As for a "simple" solution, maybe this is what you're looking for?
> 
> ...



Uhuh.  What about this one?
	
	



```
( commA && commB && commC ) > /tmp/log.$$ 2>&1 && rm /tmp/log.$$ || cat /tmp/log.$$
```


----------



## aragon (Jan 29, 2010)

That is simpler, but I think it will mix outputs together, ie. if commB fails and commA produced output (without failing), commA and commB outputs would be mixed.

Maybe some demarcation echos can be added:


```
( echo commA starting... && commA && echo commB starting... && commB && echo commC starting... && commC ) > /tmp/log.$$ 2>&1 && rm /tmp/log.$$ || cat /tmp/log.$$
```


----------



## DutchDaemon (Jan 29, 2010)

Like phoenix said: if you need more than one command started from cron, script the whole thing, and run it through [cmd=]sh -x(v)[/cmd] a few times to see if you have everything right. Cron is not designed as a fully functional shell, it is just a jumping board to launch external programs or scripts.


----------



## Seeker (Jan 29, 2010)

Ok, guys thanks!
I get it. Scripting is a way to go...

Now, I put in cron line: */path/to/script*

It is intended to be executed by user and by cron.
Here I need some sh scripting, in a way that script can recognize it has been executed by a cron _in the name of a root_:

```
echo "HEEEELOOO!!" && portsnap [B]fetch[/B] update > /dev/null && echo "HEEEELOOO!!"
```
becomes:

```
echo "HEEEELOOO!!" && portsnap [B]cron[/B] update > /dev/null && echo "HEEEELOOO!!"
```
So that in bold will be some variable in */path/to/script*.

Now I need code snippet, that detects if cron is executing */path/to/script*, possibly in a same way *portsnap* detects it.(It will halt if invoked with fetch, instead of cron arg)


----------



## DutchDaemon (Jan 29, 2010)

Just add a command-line variable in cron, and import it into the script.

Start from cron like:


```
/path/to/script fromcron
```

In script:


```
if [ $1 = "fromcron" ]
then
var=cron
else
var=fetch
fi

portsnap $var update
```

Or use/adjust my script


----------

