4

dir has two regular files.

file1 has abc\n, file2 has def\n. Compress these two files with gzip, as shown below,

#ls
#echo 'abc\n' > file1
#echo 'def\n' > file2
#gzip file1
#gzip file2
#ls
file1.gz  file2.gz

After I cat the content,

#find . -type f  -name "*.gz" -exec zgrep -Iq . \{} \; -exec zcat \{} \;
def\n
abc\n

I do not get the content of files in order of the file creation time. The expected output should be always abc\ndef\n.

Interesting observation: Actual output is sometime, def\nabc\n and sometimes abc\ndef\n

Question:

How to find files in order(decreasing/increasing) of timestamp?

3

The order of files reported by find is opaque to the user. It can be the order they appear in the directory. Some find implementations reorder them by inode number or other criteria in an attempt to improve performance. The only way one may alter the order is via the -depth predicate that tells find to process/output leaves before the branch they're on.

As an alternative to find, you could use zsh's recursive glob feature:

zgrep whatever ./**/*.gz(D.Om)

The Om glob qualifier is to sort by last-modification time (oldest first). . is for regular-files only (equivalent of find's -type f), D is to include hidden (Dot) ones like find would by default.

If you get a arg list too long error, you can use zargs:

autoload -U zargs # best in ~/.zshrc
zargs ./**/*.gz(D.Om) -- zgrep whatever

With bash (or any shell supporting Ksh-style process substitution) and recent GNU tools, an equivalent would be:

xargs -r0a <(
  export LC_ALL=C
  find . -type f -name '*.gz' -printf '%T@\t%p\0' |
    sort -zn | cut -zf2-) zgrep whatever
1

One option is to output the file timestamp along with the file path, sort by it, and then remove it:

find -type f -name "*.gz" -printf '%C@\t%p\n'|sort -nk1|cut -f2-|xargs zcat 

Note that if your filenames can contain potentially unsafe characters (such as spaces), just replace

xargs zcat 

with

xargs -d "\n" zcat 

and if you need to accommodate for the newlines in the filenames, you can use a null byte to terminate records, as detailed in @stéphane-chazelas answer (through that is rarely a problem in practice).

  • That assumes file names don't contain blanks, newline, quotes or backslashes. Note that sort -nk1 is the same as sort -n. – Stéphane Chazelas May 30 '17 at 12:06
1

Unfortunately the find command works in such a way that the output is not guaranteed to be in alphabetical or file age time order. You might try something like:

ls -1dtr $(find . -maxdepth 1 -type f -name '*.gz') | xargs gzcat $1
  • 2
    That assumes file names don't contain blanks, newlines, quotes, backslashes or wildcards – Stéphane Chazelas May 30 '17 at 11:32
  • This also assumes that the list of file names isn't too long to fit on a command line. – Gilles May 30 '17 at 23:08

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.