0

at folder a at time , 6pm, i create file 6 with text abc

at folder a/b at time , 7pm, i create file 7 with text abc

at folder a at time , 8pm, i create file 8 with text abc

In folder a, I want to search all files with text abc, order them by most-recently created to least- recently created. I do search by ls -hlt | grep -ir abc * my results are

6:abc
8:abc
b/7:abc

but i want the following. How do I acheive it?

8:abc
b:\7:abc
6:abc

Update : ls -lt | grep -ir abc * works well to return files with abc, oldest to newest, where as ``ls -lt` shows files new to old. Not sure why the grep disturbs flow

Rahul SK
  • 350
  • 3
  • 23
  • 1
    Most linuxs filesystems do not usually keep the time of creation of a filename. – KamilCuk Jan 07 '20 at 11:27
  • then how do you sort from last modified to acheive that expected file listing in that order – Rahul SK Jan 07 '20 at 11:29
  • I don't understand the `b:\7:abc` output, where is the `\7` coming from? Wouldn't that be `b/7:abc`? Och, is the \ the folder separator for you? Or is the filename named literally `b:\7` (4 characters)? Or did you mix with `/` as the folder separator? – KamilCuk Jan 07 '20 at 11:33
  • 1
    mistake there. its forward slash, not back. @KamilCuk – Rahul SK Jan 07 '20 at 11:38
  • Something which is not clear, do you want to sort by modification time, or is the time a part of the filename as you give in your example (filename 7 means file created 7pm) – kvantour Jan 07 '20 at 14:55

3 Answers3

0

I think that is that you want. It'll show the files with the word 'abc'. newest first.

ls -Rt1 | grep "*abc*"
Alex
  • 58
  • 1
  • 7
0

Big problems are split into small problems.

  • Find all files that contain 'abc' ignoring the case.
  • Print each filename with it's time of creation since epoch.
  • Sort the list of filanames on the date.
  • Remove the date of creation from the list leaving the filenames.

So it's:

grep -irl ABC . |
xargs -d$'\n' -n1 sh -c 'printf "%s\t%s\n" "$(stat -c "%W" "$1")" "$1"' -- |
sort -n -k1 |
cut -f2-

Tested with (notice the stat -c "%Y" vs stat -c "%W"):

rm -rf a
mkdir -p a/b
echo abc > a/6
touch -d@1 a/6
echo abc > a/b/7
touch -d@2 a/b/7
echo abc > a/8
touch -d@3 a/8

grep -irl abc ./a |
xargs -d$'\n' -n1 sh -c 'printf "%s\t%s\n" "$(stat -c "%Y" "$1")" "$1"' -- |
sort -n -k1 |
cut -f2-

on repl outputs:

./a/6
./a/b/7
./a/8
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Note that unless you are using a filesystem that records creation time `stat -c "%W"` is going to report 0 as the creation time. – William Pursell Jan 07 '20 at 13:42
0

There is a generic problem with parsing commands like ls or find. This is because filenames can become really interesting when they have special characters. You can read more about it on this Bash Pitfall and BashFAQ 20

The most accepted approach is to create a filelist, where the filenames are separated by the NULL-character (\0). GNU grep has the possibility to create such a list using the -Z flag:

-Z, --null: Output a zero byte (the ASCII NUL character) instead of the character that normally follows a file name. For example, grep -lZ outputs a zero byte after each file name instead of the usual newline. This option makes the output unambiguous, even in the presence of file names containing unusual characters like newlines. This option can be used with commands like find -print0, perl -0, sort -z, and xargs -0 to process arbitrary file names, even those that contain newline characters.

source: man grep

We can now use this in the question of the OP:

$ grep -lZR "abc" a/

will provide us with a null-separated list of files which can now be stored in an array for further processing (See Capturing output of find . -print0 into a bash array)

unset a i
while IFS= read -r -d $'\0' file; do
  a[i++]="$file"        # or however you want to process each file
done < <(grep -lZR "abc" a/)

At this point, we have now an array a which we can use to do whatever we want. For example, list all files sorted by modification time:

$ ls -lrt "${a[@]}"
Community
  • 1
  • 1
kvantour
  • 25,269
  • 4
  • 47
  • 72