quotes inside backticks inside quotes in ksh

I’m trying to get the file of the current date with the following command in HP-UX Unix:

$ ls -lrt ABC.LOG* |grep "`date +"%b %d"`"

But, it’s giving me the error:

ksh: : cannot execute
grep: can't open %d

Any suggestions?

Asked By: User123

||

The error stems from the quoting of the arguments of grep and the fact that backticks don’t do nesting very well:

grep "`date +"%b %d"`"

This is better written as

grep "`date +'%b %d'`"

… or even better,

grep "$(date +'%b %d')"

In fact, with $(...) instead of backticks, you should be able to keep the inner double quotes:

grep "$(date +"%b %d")"

An alternative to grepping the output of ls would be to do

find . -type f -name "ABC.LOG*" -ctime -1

This would find all regular files (-type f) in the current directory whose names matches the given pattern and whose ctime is less than 24 hours since the current time. A file’s ctime is the time when the last modification of the file’s data or metadata was made.

This is not exactly equivalent to what you’re trying to achieve though. This also recurses into subdirectories.

Answered By: Kusalananda

The find command can be used for the correct tool, instead of doing ls and greping result, so it’s good to note that please don’t parse ls result.

find /path/to/ -type f -name "ABC.LOG*$(date +"%b %d")*"

Above is looking for today’s date in filesname, if you are looking for the files created/modified in today’s date, you could use find as this way (GNU version of find):

find /path/to -type f -name "ABC.LOG*" -newermt 00:00

Or in last 24Hours:

find /path/to -type f -name "ABC.LOG*" -newermt yesterday

Or as follow:

find /path/to -type f -name "ABC.LOG*" -newermt "$(date +"%b %d")"
Answered By: αғsнιη

In the Korn shell, like in the Bourne shell, quotes and backticks (the archaic form of command substitution) can be unmatched, and you have to help the tokeniser to tell where backticks end. Inside backticks there’s another level of backslash processing.

echo "`date"

works and is the same as:

echo "`date`"
echo "$(date)"

And:

echo `echo "foo`

works and is the same as:

echo `echo "foo"`
echo $(echo "foo")

If you do:

grep "`date +"%b %d"`"

That’s taken as a grep word and then "`date +" (unclosed backticks inside double quotes) concatenated with %b and then %d concatenated with another unclosed backticks inside double-quotes: "`". So it’s like

grep "$(date +)"%b %d"$()"

(except that for some reason, while echo "``" or echo "$()" would not cause an error, in echo "`", the shell will try to execute a command with an empty name (as if you had written echo "$("")").

So here, you need to use backslash to help the parser:

grep "`date +"%b %d"`"

Those backslashes are actually removed. It is date +"%b %d" that is being evaluated by the subshell in the command substitution.

Here, since ksh accepts unclosed quotes, you could actually also do:

grep "`date +"%b %d"

(not that I would advise doing that).

That’s also how you can get nested backticks as in:

echo "`echo "`echo \"a  b\"`"`"

A good example why nobody hardly ever uses that syntax and use the $(...) newer form (introduced by ksh in the early 80s):

echo "$(echo "$(echo "a  b")")"

Now, for your particular problem, it looks like you want to list ABC.LOG* files in the current directory that were last-modified today. For that, you could do:

touch -t "$(date +%Y%m%d0000)" .start-of-day &&
  find . ! -name . -prune -name 'ABC.LOG.*' 
    -newer .start-of-day -type f -exec ls -lrtd {} + &&
  rm -f .start-of-day
Answered By: Stéphane Chazelas
Categories: Answers Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.