Ray Toal
Ray Toal

Reputation: 88378

Use of || in a bash pipeline

I have a directory with zero or more files with names like

on_common_20131020.xml
on_common_20131021.xml
on_common_20131022.xml

and so on. In order to extract the datestamp of the most recent one, I know I can use the following hack

ls -rt on_common* | tail -n 1 | egrep -o '[0-9]{8}'

(though if there is a better way I'd love to know). Now the thing is, I want to capture this value in a script, so I have the following line:

RECENT=$(ls -rt on_common* | tail -n 1 | egrep -o '[0-9]{8}')

However, there may not be any such files in the directory, in which case ls will fail, and I want the value of RECENT to be, in that case, 00010101. I know how to use ' c1 || c2' to execute command c2 if and only if command c1 fails, but was unable to find anything that would give me the equivalent of this pseudo-Bash:

RECENT=$(ls -rt on_common* | tail -n 1 | egrep -o '[0-9]{8}') || '00010101'  # WRONG

Yes I can do this with if...fi, but is there a single expression form?

EDIT

It turns out there was just a missing echo. The Bash syntax says:

A list is a sequence of one or more pipelines separated by one of the operators ‘;’, ‘&’, ‘&&’, or ‘||’, and optionally terminated by one of ‘;’, ‘&’, or a newline.

So I was close in that pipelines can be separated by || but the expression to the right of the || was not a pipeline (it wasn't even a command).

And another pedantic note for anyone that ends up here. Using -t in ls when there is a datestamp in the filename is pretty dangerous; someone could touch a filename with a datesamp in it. I ended up with:

RECENT=$(ls -1 on_common* 2>/dev/null | sort -r | egrep -om1 '[0-9]{8}' || echo '00010101')

which is a combination of Blue Moon's (redirect to dev/null) and jaap's answer (lack on inner parentheses and -m for egrep).

Upvotes: 2

Views: 116

Answers (3)

Idriss Neumann
Idriss Neumann

Reputation: 3838

You could use a sub-shell like this :

command1 |(command2 || <treatment if command2 fails>)
var=$(command1 |(command2 || <treatment if command2 fails>)) # to get the commands suite output in a variable

And if you want execute treatment only if command1 fails :

(command1 || <treatment if command1 fails>)|command2
var=$((command1 || <treatment if command1 fails>)|command2) # to get the commands suite output in a variable

Upvotes: 0

jaap
jaap

Reputation: 5959

First, your search expression can be a bit shorter

ls -t on_common* | egrep -om1 '[0-9]{8}'

For the second part, this should work

RECENT=$(ls -t on_common* | egrep -om1 '[0-9]{8}' || echo "0001-01-01")

Upvotes: 1

P.P
P.P

Reputation: 121347

    RECENT=$((ls -rt on_common* 2>/dev/null| tail -n 1 | egrep -o '[0-9]{8}') 
|| echo '0001-01-01')

will do the equivalent of c1 || c2 as you desired.

Note that I redirected stderr to /dev/null ( 2>/dev/null) in case ls fails. If do you want to see the error, you can remove it.

Upvotes: 2

Related Questions