I normally use the for construct in ksh to quickly iterate over a list of files to perform some action on it. It doesn’t seem to work in this scenario:
The file info looks like:
$ ls -l tmp.*
rw------- 1 op general 375 Jul 25 04:09 tmp.zzyhsg4
...
so on. Basically a lot of tmp.* files.
Now when I try
$ ls -lS | grep 'Jul 25' | grep 'tmp.*' | cut -d' ' -f9 | more
tmp.zzyhsg4
..
it will print only the file names as expected.
However when I try the below
$ for i in `ls -lS | grep 'Jul 25' | grep 'tmp.*' | cut -d' ' -f9`
>do
>echo $i
>done
This does not print the name of all the files starting with tmp.* which were created on Jul 25 sorted by size. It prints the size column. Interestingly if I replace the f10 by f6 for the cut it will correctly print the month column. It starts to break after f9.
Any ideas ?
I can’t reproduce exactly what you describe, but I have some suggestions to write more reliable commands.
cut -d' 'separates fields by spaces. If you have two spaces in a row, there’s an empty field between them. So if you try withAug 1instead ofJul 25, the file name column is shifted by 1. And if you try with files that are more than 6 months old, the (5-character) time is replaced by a space followed by the 4-digit year. Also, depending on your version oflsthere may be more than one space between some columns. Yet another issue is that some versions oflsdon’t display thegroupcolumn. And then some file names contain spaces. And some file names contain special characters thatlsmay display as?. In summary, you can’t parse the output ofls -lby counting spaces, and you can’t even parse the output ofls -lby counting whitespace-delimited fields. Just don’t parse the output of ls.The standard command for generating lists of names of existing files is
find. Since you mention Linux, I’ll mention options that work with GNU find (the version you get on Linux) but not on other unixes.Let’s start simple: list the files called
tmp.*in the current directory.We want only the files created on July 25, that’s 7 days ago.
This is fragile since it won’t work tomorrow. The usual way to specify a precise date is to create files dated at the earliest and latest allowable times and tell
findto only return files dated between these two.The
findcommand explores subdirectories recursively. If you don’t want this:If you want the files sorted by size:
Finally, if you want to operate on the files, never use
findin backticks, the way you usedls, because this will fail if the file names contain whitespace or some special characters, because the shell splits the output of`command`at whitespace and then does globbing on the resulting words. Instead, use the-execoption tofind; the;version executesmycommandonce per file with{}replaced by the file name, whereas the+version usually invokesmycommandonly once with{}replaced by the list of file names.