I've wrote script that suppose to find all directories that contains number and dots or @tmp in their name, sort it by date and then save in variable 3rd result of statement. But this one is always giving me first result of query. How can I get proper result?

TL;DR I want to sort the matching directories by date and print the third directory name in that list

OLDDATA=`find . \( -name '*@tmp' -o -regex '.*/[0-9.]+' \) -exec ls -t {} + | awk "NR==3 { print }" `

Example of ls -t result

./ ./ ./ ./
./ ./ ./ ./
./ ./ ./ ./
./ ./ ./ ./

closed as unclear what you're asking by αғsнιη, Stephen Rauch, Wouter Verhelst, G-Man, DarkHeart Nov 14 '17 at 6:31

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    Can I check what you're trying to achieve here, please. You want to sort the directories matching your RE by date, and print the third file name that's in these directories, regardless of which directory it appears in? Or you want to sort the matching directories by date and print the third directory name in that list? Or something else? – roaima Nov 12 '17 at 17:50
  • @roaima "Or you want to sort the matching directories by date and print the third directory name in that list?" <- this I want to get 3rd newest directory that has only numbers, dots or @tmp in it's name, and after it, use it in this statement find . -not -newer $OLDDATA -and \( -name '*@tmp' -o -regex '.*/[0-9.]+' \) -exec rm -r {} \; So I can remove older files then this one. Because I need to save those 3 files. But main directory contains also other directories with names that contains characters - so I need to exclude them, because those shouldn't take part in this process – harcotlupus Nov 12 '17 at 17:59
  • 1
    Please put that clarification in your question so everyone can read it easily. – roaima Nov 12 '17 at 19:00
  • When you say you're looking for directories that contain numbers or doors in their name, would cream47 be acceptable because it contains numbers in its name? It did you mean that the names must be exclusively comprised of numbers and dots? – roaima Nov 12 '17 at 20:38
  • @roaima OP's recent questions shows s/he is following a simple things but in different ways and each question has extra new requirement a bit. Actually all his/her question has same one goal but I think s/he asking questions with not telling us what s/he wants actually do rather than providing a command and focus on which it doesn't work. – αғsнιη Nov 13 '17 at 9:06

The correct statement in your particular case should look as below:

find . \( -name '*@tmp' -o -regex '.*/[0-9.]+' \) -exec ls -t {} \; | awk 'NR==3'
  • @harcotlupus, your initial statement looks like adventure, that's why I wrote particular case. – RomanPerekhrest Nov 12 '17 at 17:44
  • I've output like this, and this statement is picking first one not 3rd... any ideas why? ./ ./ ./ ./ ./ ./ ./ ./ ./ ./ ./ ./ ./ ./ ./ ./ – harcotlupus Nov 12 '17 at 17:44
  • @RomanPerekhrest don't know why, version with ` \; ` doesn't push anything into variable.. – harcotlupus Nov 12 '17 at 17:45

I would probably go for this approach (split over several lines for readability; just join them together to get a single line):

ls -td $(
    find . -maxdepth 1 -type d \( -name '@tmp' -o -regex '.*/[0-9.]+' \)
) |
    sed -n '3{p;q}'

This finds the matching directory names, lists them in date order, and prints just the third entry from that list. (Using ls to sort the output from find is acceptable in this instance because we can be assured none of the path names contains whitespace or any other awkward character. In the general case this is a bad assumption.)

It won't match any of your directories that end with a colon (:) though (but nor would your original RE from your question).

I thought it might be useful to explain why your original statement wasn't achieving (what I think is) your stated aim.

Let's look at the find:

find . \( -name '*@tmp' -o -regex '.*/[0-9.]+' \) -exec ls -t {} +

This matches files or directories whose names either end with @tmp or are comprised only of the digits 0..9 or a dot .. When a file or directory matching these two patterns is found, it's added to a list. The list does not necessarily contain all of your matches and you should not assume it does. When the list is "long enough" it is passed to ls -t. You may get two or more executions of ls -t, each of which sorts and lists a different set of file and directory names.

On my systems, ls -t lists files first, in descending order by date modified. It them sorts the directory names in descending order by date modified, and for each one it prints the name and its contents (also sorted by descending date order). To omit the contents you would need to use ls -td.

To be safe, you cannot even use find ... -type d ... -exec ls -dt {} +, because you cannot know how many directory names will be passed to the list represented by {}.

Let's look at the awk:

awk "NR==3 { print }"

This is fine, although I would have tended to use { print; exit} to stop processing immediately the third item had been printed.

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