On my SunOS system, I'm trying to find all files created after 7 PM using csh, ls, and awk.

ls -l  "${Source_files_Dir}"/*.zip| awk -v today="$(date "+%b %d")" '{
date=$6" "$7; time=$8; if (date == today && substr(time,1,2) >= 19)
print $9 }'|xargs -n 1 basename

This command works in ksh but not in csh. How can I achieve this in csh?

Note: -newermt option is not supported by find on SunOS, so I tried to use the above ls command.

  • If it works in ksh, then why not use ksh? What errors do you get from csh? What Unix are you on? What implementation of find do you have access to?
    – Kusalananda
    Commented Apr 22 at 13:19
  • Hi @Kusalananda all scripts are in csh, its on SunOS
    – Aravind
    Commented Apr 22 at 13:22
  • 1
    @Aravind, Solaris will have ksh. Since Solaris 11 (aka SunOS 5.11), its /bin/sh is even ksh93 which has date manipulation built in. Commented Apr 22 at 13:45
  • 1
    As a new starting point: Don't parse the output of ls and don't write scripts with csh. Also make sure if you're on Solaris that you use /usr/xpg[4 or 6]/bin/awk or nawk, not /usr/bin/awk.
    – Ed Morton
    Commented Apr 22 at 21:27

2 Answers 2


That approach is quite flaky anyway, you would be better of using perl:

perl -MPOSIX -MFile::Basename -le '@start = localtime; @start[0..2] = (0,0,19); $start = mktime(@start); for (@ARGV) {print basename$_ if @s = stat$_ and $s[9] >= $start}' -- "$Source_files_Dir"/*.zip

Not sure why you'd be using csh in this century, but note that the above doesn't work properly in csh if $Source_files_Dir contains newline characters. Replacing "$Source_files" with $Source_files:q would be better in csh (but not work any longer in other shells).

Solaris (formerly known as SunOS) would also usually have zsh installed, where it's just a matter of doing:

autoload age
print -rC1 -- $Source_files_Dir/*.zip(Ne[age 19:00]:t)

Listing some of the problems with your approach:

  • ls -l "${Source_files_Dir}"/*.zip: if $Source_files_Dir starts with -, it will be treated as an option by ls. Generally, you need -- to mark the end of options if what follows is variable.
  • if any of the zip files are of type directory, its their contents that will be listed. When using ls with a glob or generally variable data, you generally want to use the -d option: ls -ld -- ...
  • In csh specifically, if $Source_files_Dir contains newline characters, that will cause a syntax error. $Source_files_Dir:q is better in csh as noted above.
  • In any case, you're assuming the file paths (file names and symlink targets which ls -l also reports) don't contain newline characters as you're processing the output of ls line based.
  • You're assuming the date/time is in fields 6, 7, 8 which will fall apart if user or group names contain whitespace. Using -n instead of (or in addition to) -l to get numeric uid/gids would make it more robust (and avoid the potentially costly translation to names).
  • date +%d outputs a 0-padded number, while with many ls implementations and in many locales (and that's a POSIX requirement in the C/POSIX locale), ls -l outputs a space-padded number (date +%e).
  • ls -l outputs Mon dd HH:MM for recent dates not in the future, but Mon dd YYYY for others which your approach doesn't handle.
  • without the -L option, for symlinks, it's the modification time of the symlink as opposed to that of the zip file it points to that will be listed. perl's stat() or zsh's age work with the mtime of the target.
  • with your {print $9}, in addition to user/group names not containing whitespace, you're assuming the file paths don't either.
  • using xargs on that raw output will fail if file paths contain backslashes or quotes, and by not running it in the C locale, on file names that are not text encoded in the locale's encoding.
  • if there's no unhidden zip file in the directory, in csh, you'll get a No match error and ls won't be run (which at least is better than the Bourne-style behaviour where ls is called with the pattern literally), but xargs will still be run, and basename will still be run once with no argument likely causing a confusing error.

I got answer for csh, instead of '$' used backticks stored today's date into a variable today rather getting it in awk.

set today=`date "+%b %d"`
ls -l "$Source_files_Dir"/*.zip | awk -v today="$today" ' \
{ \
    date=$6" "$7; \
    time=$8; \
    if (date == today && substr(time,1,2) >= 19) print $9; \
}'|xargs -n 1 basename
  • 1
    today=`date "+%b %d"` is not csh syntax for variable assignment. You'd need set today = "`date '+%b %d'`", though see the other problems with that approach in my answer. Commented Apr 25 at 8:37
  • Hi @StéphaneChazelas yes, you are right. I missed to add set here, will add it. Thank you for your answer and I will modify my ls command as you suggested.
    – Aravind
    Commented Apr 25 at 12:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .