3

This command works well in command prompt :

 ]$ ls -ltr ../cmxserver.log*|grep "`date | awk '{print $2" "$3}'`"|cut -d "/" -f2
 cmxserver.log.2
 cmxserver.log.1
 cmxserver.log

However, using this in for loop gives error bash: syntax error near unexpected token `|'

   ]$for y in `ls -ltr ../cmxserver.log*|grep "`date | awk '{print $2" "$3}'`"|cut -d "/" -f2`

 -bash: syntax error near unexpected token `|'

Any idea ?

Thanks

6
  • 4
    It's not sure what you're trying to do with your command - can you explain it? It looks like it can be simplified a lot. In general, parsing ls is something to be avoided. Commented Sep 15, 2015 at 10:39
  • 3
    Step 1: replace the deprecated ticks (which cannot be nested) with $(...) which can. Commented Sep 15, 2015 at 10:45
  • @EdMorton Yep they haven't escaped the inside backticks so the command is being broken. Best to just use $() which can be easily nested. Commented Sep 15, 2015 at 10:50
  • You might be able to skip awk altogether if you specify the format to the date command Commented Sep 15, 2015 at 11:00
  • See also mywiki.wooledge.org/ParsingLs and mywiki.wooledge.org/BashFAQ/087 Commented Sep 15, 2015 at 13:44

2 Answers 2

4

The whole line can be solved by find command:

find .. -maxdepth 1 -mtime -1 -daystart -name 'cmxserver.log*' -printf "%f\n"
  • .. - directory where to search
  • -maxdepth 1 - don't go recursive to subdirectories
  • -mtime -1 - only today's files
  • -daystart - count the day since midnight, not last 24 hrs
  • -name 'cmxserver.log*' - filenames
  • -printf "%f\n" - print only basename
Sign up to request clarification or add additional context in comments.

4 Comments

Worth mentioning that -printf is a GNU extension to find, so this won't work everywhere.
Thanks Tom for reply however it will result the files which are less than 24 hours old. Not necessarily created after 12:00 AM on the same day ?
Yes, you are right, it is 24 hours period. It can be fixed by adding -daystart param. I'm fixing the answer.
Thanks Mitroo but still -daystart seem to make any difference as it shows files older than 24 hours.
2

You probably understood what you meant when you typed:

for y in `ls -ltr ../cmxserver.log*|grep "`date | awk '{print $2" "$3}'`"|cut -d "/" -f2`

But you have managed to completely confuse bash. Bash (and other shells) don't nest backticks (`) unless the inner ones are backslashed. As written, the second backtick is considered to close the first one, resulting in the command ls -ltr ../cmxserver.log*|grep ". Since you did not put a space before date, the word date is parsed as part of the word including the command substitution. Similarly, the single-quoted '{print $2"$3}' is parsed as being prepended to the backticked command "|cut -d "/" -f2.

Of course, both of those backticked commands are syntax errors because they contain unclosed double quotes, but before bash reaches the point of parsing and executing the commands, it is left with something which roughly speaking looks like:

for y in word1 | awk word2

which is a syntax error because the pipe symbol can only appear between complete commands, and for y in word1 is not a complete command.

Backticks are deprecated. Stop using them.

If you had written:

   for y in $(ls -ltr ../cmxserver.log* |
              grep "$(date | awk '{print $2" "$3}')" |
              cut -d "/" -f2)

both bash and human readers would have found the expression much easier to parse, and bash would have parsed it as you expected.

Having said that, it is never a good idea to try to parse ls output, and it is never necessary to parse date output because you can specify a format string; in this case, you could have used date +"%b %d" to get the month and day. (First link courtesy of a comment by Charles Duffy.)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.