2

I am trying to remove files within a bash script.

I can list the latest file with:

ls | grep core | tail -n 1

and rename it like keep-core-2994-xyz.bin, then remove the rest with:

rm -f core-*

and then rename the latest to the original. In this way, I can keep the latest file and remove the rest. This works fine for this scenario:

-rw-------  1 root root  47M Sep  3  2017 core-2994-xyz.bin
-rw-------  1 root root  47M Sep  3  2017 core-3012-xyz.bin
-rw-------  1 root root  79M Sep  3  2017 core-3106-xyz.bin

However, this one: core-10000-xyz.bin causes trouble:

-rw-r--r--  1 root root  55M Sep  3  2017 core-10000-xyz.bin
-rw-------  1 root root  47M Sep  3  2017 core-3012-xyz.bin
-rw-------  1 root root  79M Sep  3  2017 core-3106-xyz.bin

... because this time, I need to keep the one I want with head, not with tail.

Is there any effective way to remove files except the latest one which were created by this order? (Here, core-3012-xyz.bin)

The file timestamps are unreliable; this is an embedded device and timestamps can change due to the internet connection, so I can't list them by timestamp.

This is an embedded device and I don't want to compile it with zsh; I'd like a bash-only solution, please.

Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
obayhan
  • 139
  • 6

2 Answers2

4

With zsh:

rm -f -- *core*(n[1,-2])

Where the n glob qualifier turns on numericglobsort for that one glob expansion and [1,-2] selects the first to second last.

Or:

rm -f core-<1-4294967295>-xyz.bin(n.[1,-2])

If you want to make it more specific, where <1-2147483647> matches on sequences of digits that represent numbers in the range of valid pid numbers and the . qualifier restricts the expansion to regular files only.

Note that core-bar-123 would sort before core-bar-1000 but also before core-foo-1. The numeric sort is used when it comes to comparing numbers when the part leading up to them is the same. Here core-bar sorts before core-foo. Adding numbers to either won't change that.

To only consider the numbers when sorting, you could do something like:

extract_numbers() {
  set -o localoptions -o extendedglob
  REPLY=${${${REPLY//[^0-9]##/-}#-}%-}
}
rm -f --  *<->*(.no+extract_numbers[1,-2])

Where extract_numbers converts some123file5123with3numbers to 123-5123-3 which is then used for numeric ordering.

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
  • I like this a lot, but to be fair, the question has a [tag:bash] tag! – Marcus Müller May 16 '22 at 15:41
  • 1
    @MarcusMüller, sure. In `bash`, just do `zsh -c 'that code'` but why would anyone still use `bash` in this day and age :-b. In anycase, the answer would be useful to users landing here with similar requirements and not being limited to using bash – Stéphane Chazelas May 16 '22 at 15:46
  • Somehow, I do agree ;) – Marcus Müller May 16 '22 at 15:46
  • @StéphaneChazelas because as i wrote in question this is an embedded device and there is no reason to compile it together with zsh and believe me this is our last concern. – obayhan May 21 '22 at 22:26
0

Oh i found the solution.

ls -v | grep core | tail -n 1

will do the trick.

Reference:

List files sorted numerically

obayhan
  • 139
  • 6
  • 1
    I'm sorry I've downvoted this, but: ***Never*** parse `ls` output. For example, this all breaks when a file has a newline in its name – which is a perfectly legal character. So, not really a solution. – Marcus Müller May 16 '22 at 15:42
  • also note that as Stéphane has pointed out, you could at least restrict your `ls` to only look into files that are called `core-*` to begin with. – Marcus Müller May 16 '22 at 15:44
  • 1
    But: you've linked to a good resource, but you focused on the answer producing output meant for *human* consumption, not for *computer* consumption. [This](https://unix.stackexchange.com/a/33988/106650) answer uses the same "listing" method that Stéphane uses in their answer here. However, the "hard" part is selecting only the right file, and that's what's missing. – Marcus Müller May 16 '22 at 15:47
  • Your attempt @obayhan is incomplete, it's not going to delete anything. – tansy May 16 '22 at 21:11
  • `$ ls -v -1 core-* | tail -n 1 | xargs rm -f` – tansy May 16 '22 at 21:12
  • 1
    @MarcusMüller these are dump output files controlled by us, they don't have a chance get an empty or non-alphanumeric string in their names.So there is no reason not to parse "ls output" (: + this was an example, in real system dumps can get prefixes like xyz-core-1234, thats the reason of the grep. + i can guarantee there is anything else in there containing "*core*" Anyway thanks for the reminders to produce a "common" answer but my problem is not common. However they are unrelated to my question. As i said it is an embedded linux and i have all control over that directory. – obayhan May 21 '22 at 22:38
  • 1
    @MarcusMüller so please dont think it is an uncontrolled Desktop – obayhan May 21 '22 at 22:40
  • 1
    @tansy please read the question carefully – obayhan May 21 '22 at 22:40