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.

1
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.

6
  • find is good. But your implementation will break when file names contain spaces. (A sufficiently common situation that it's worth covering. I'm not going to talk about other non-printables such as \n.) – roaima Jan 17 '18 at 11:51
  • Damn, I was afraid of that. I was avoiding this because on my linux I have to use newer which requires a file as a reference but if it's the only way then that's that. Thanks a lot for your answer – TheLovelySausage Jan 17 '18 at 12:07
  • @Trent you've tagged with centos so why are you constrained to -newer rather than -newermt? – roaima Jan 17 '18 at 12:13
  • I'm not sure, I couldn't get newermt to work on my system a while ago so had to use newer. I don't remember the details though – TheLovelySausage Jan 17 '18 at 12:15
  • @roaima yes, you are right! depending on what the use-case is i would suggest to use find's -exec in order to apply the command(s) to the given file... – hiro protagonist Jan 17 '18 at 12:18
2

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.

1
  • 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 – roaima 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.