1

Assume I have 3 folders in different directories, some of them containing some more subfolders, and in each folder/subfolder I have text files named test1, test2, test3 etc..., which contain the string hello in some way. It can be just hello, it can be helloJASKFNASKFN etc.

How can I display a sorted list of those files? Say I want to sort by their names, or by the modified date. I do understand that I can use the grep or find command to search and display those files, but I'm not sure how can I display them in a sorted way.

1
  • 2
    On what operating system (Unix? Linux? macOS? something else)? Also, what shell do you use? Bash? Zsh? Something else? And how do you want to sort? Sorting by name and by modification date are two completely separate issues. And what do your file names look at? Do solutions need to be able to deal with arbitrary file names (even really weird ones with newlines)? Or can we assume simple file names with no whitespace or globbing characters? Please edit your question and clarify.
    – terdon
    Nov 3, 2021 at 10:24

1 Answer 1

1

It's easier if you sort the list of files first before passing it to grep:

In zsh, you can do:

grep -le hello -- **/test<->(.)

Which looks for hello in the contents of files whose name is test followed by one or more decimal digits (<-> being a form of the <x-y> pattern to match ranges of numbers), in or below the current working directory, skipping hidden directories.

Glob expansions by default are sorted by name.

To sort by modification time, use (.om) instead of (.). or (.oL) by size. See info zsh qualifiers for the list of glob qualifiers and the list of criteria the o qualifier can sort by.

Replace o with O to reverse the order (On to sort in reverse by name).

Use (.n) for the sort by name to be numerical (test10 to come after test9, not in between test1 and test2).

If you run into a Too many arguments error (caused by a limitation of the execve() system call of most system):

autoload -Uz zargs # best in ~/.zshrc
zargs -- **/test<->(.) -- grep -le hello --

With GNU tools and any shell (except (t)csh where you'd need to put the command on one line):

To sort by name:

LC_ALL=C find . -regextype posix-extended -name '.?*' -prune -o \
  -regex '.*/test[0-9]+' -type f -print0 |
  sort -z |
  xargs -r0 grep -le hello --

(add the -V option to sort for a numerical sort)

To sort by modification time:

LC_ALL=C find . -regextype posix-extended -name '.?*' -prune -o \
  -regex '.*/test[0-9]+' -type f -printf '%T@\t%p\0' |
  sort -zrn |
  cut -zf2- |
  xargs -r0 grep -le hello --

Add / remove -r to sort to reverse the order.

11
  • I tred for example to sort with GNU tools by name, this is the input : -VirtualBox:~$ LC_ALL=C find . -regextype posix-extended -name '.?*' -prune -o \ > -regex '.*/test[0-9]+' -type f -print0 | > sort -z | > xargs -r0 grep -le hello -- But I get no output. What went wrong? Nov 3, 2021 at 8:57
  • Also the first command you mentioned gives the output : bash: .: filename argument required .: usage: . filename [arguments] bash: -/dev/fd/62: No such file or directory bash: .: filename argument required And when I try to write the lines you say to write if an arguments error comes up, the output is "autoload: command not found" Nov 3, 2021 at 8:58
  • @DirichletIsaPartyPooper as the answer says: you need to use zsh, not bash.
    – terdon
    Nov 3, 2021 at 10:24
  • @DirichletIsaPartyPooper, do you have a file that is named like test<digits> and contains hello in or below the current working directory? Nov 3, 2021 at 10:39
  • @StéphaneChazelas both in and below Nov 3, 2021 at 10:41

You must log in to answer this question.

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