0

I have a Bash Script that is intended to locate files that are created on a specific date. It is working as bellow.

#!/bin/bash

LOCATION="/tmp/testfiles"
DATE="Jan 10"
COMMAND="ls -l ${LOCATION} | grep '${DATE}'"

for FILE in `eval $COMMAND`
do
    echo $FILE
done

It is locating the file that I expect it to

-rw-rw-rw- 1 root root  9485 Jan 10 10:00 test01.log

But the bash for loop is looping through all of the fields of the ls -l command so I am ending up with

-rw-rw-rw-
1
root
root
9485
Jan
10
10:00
test01.log

Which I don't want. Is it possible to extract the filename from an ls -l command in order to keep the loop from processing all of the fields.

I can't use just ls in this case because I need to know the date in order for the grep to work.

PS. I know it's not recommended to store commands into variables but I need it like that for now, I will probably change it at a later stage.

sourcejedi
  • 50,249

3 Answers3

4

this should print all the paths of the files modified between the given dates:

find . -type f -newermt '2018-01-17' ! -newermt '2018-01-18'

that should work when used in your script provided none of the file names contain space, tab, newline and wildcard characters (and you haven't modified $IFS):

FILES=$(find /your/path -type f -newermt '2018-01-17' ! -newermt '2018-01-18')

for file in $FILES; do
    echo "${file}"
done 

it will print the paths and not just the filenames.

depending on what you want to do with those files also consider executing the commands on the files direcly with find -exec command.

3

Using the output of any form of the ls command in shell scripts is almost universally highly discouraged. Even were you to use ls -1 (that's a number, "one") instead of ls -l, you would have to deal with filenames containing embedded spaces, etc.

Instead, use the find command, with the -print0 option for safe printing, and with the -ctime option for limiting to a specific file creation time.

user1404316
  • 3,078
  • 3
    -ctime is NOT file creation time. It's the time the inode was last changed. Most Linux/UNIX filesystems do not store creation time, just the date/time the file was last modified. Reference that with -mtime – Chris Davies Jan 17 '18 at 11:48
2

To perform this task safely you should not parse ls, and you should avoid using eval whenever possible. In this suggestion I've also protected the code against spaces and strange characters in the filenames:

date="Jan 10 2017"
find -type f -newermt "$date" \! -newermt "$date + 1 day" -printf '%P\0' |
    while IFS= read -r -d $'\000' f;
    do
        echo ">> $f <<"
    done

If you just want to capture the filename you don't need the while read loop and you can also use find ... -printf "%P" without the trailing \0.

Chris Davies
  • 116,213
  • 16
  • 160
  • 287