How to Sort File Names by Specific Part in Linux

How to sort by specific 'field' in filename

like this:
ls | sort -t '_' -k 2

-t is separator and -k is column

Linux - Sort files by part of name (no delimiters)

This will do the sort:

sort -k1.1,1.8 -k1.9n

That defines two keys, the first one being a fixed-length 8-character key (field one, characters 1 through 8), and the secondary key being a numeric key starting at field one character 9 (and extending to the end of the line).

Numeric sorting uses whatever number it finds at the beginning of the key, so you don't need to get more sophisticated. But if you want to be more precise, you could tell sort to use . to delimit fields, and then use three keys:

sort -t. -k1.1,1.8 -k1.9,1n -k2

You might need this with a POSIX-standard sort utility, if your filenames have varying extensions and you want the extensions to affect the sort. GNU sort (used on Linux) appears to use the entire key in a numeric sort, but the POSIX standard suggests that a numeric sort key consists only of the numeric part.

Unix - Find and Sort by part of filename

You can do it in a pipeline like this:

# List files
ls |

# Include the sorting key in the front as well
sed -E 's/^(.*)([0-9]+)\.txt$/\2\t\1\2.txt/' |

# Sort on the sorting key
sort -n |

# Remove the sorting key
cut -f2-

# Grab the first letter
cut -c1

Output:

D                                                                                                           
C
A
B
E

Bash sort files by filename containing year and abbreviated month

Try this command:

ls dir1/dir2/dir3/file_name_2017_v_*.exp.var.txt | sort -t '.' -k 1.33,1.36n -k 2,2M

Or use _ as the field-separator:

ls dir1/dir2/dir3/file_name_2017_v_*.exp.var.txt | sort -t '_' -k 5.1,5.4n -k 5.6,5.8M

If years that are different before and after the v, need to add another -k:

ls dir1/dir2/dir3/file_name_*_v_*.exp.var.txt | sort -t '_' -k 3.1,3.4n -k 5.1,5.4n -k 5.6,5.8M

Example(Update):

$ mkdir -p dir1/dir2/dir3
$ touch dir1/dir2/dir3/file_name_2017_v_201{5..7}.{Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec}.exp.var.txt
$ ls dir1/dir2/dir3/file_name_2017_v_*.exp.var.txt | sort -t '.' -k 1.33,1.36n -k 2,2M
$ ls dir1/dir2/dir3/file_name_2017_v_*.exp.var.txt | sort -t '_' -k 5.1,5.4n -k 5.6,5.8M
dir1/dir2/dir3/file_name_2017_v_2015.Jan.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2015.Feb.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2015.Mar.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2015.Apr.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2015.May.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2015.Jun.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2015.Jul.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2015.Aug.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2015.Sep.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2015.Oct.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2015.Nov.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2015.Dec.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2016.Jan.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2016.Feb.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2016.Mar.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2016.Apr.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2016.May.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2016.Jun.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2016.Jul.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2016.Aug.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2016.Sep.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2016.Oct.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2016.Nov.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2016.Dec.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2017.Jan.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2017.Feb.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2017.Mar.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2017.Apr.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2017.May.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2017.Jun.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2017.Jul.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2017.Aug.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2017.Sep.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2017.Oct.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2017.Nov.exp.var.txt
dir1/dir2/dir3/file_name_2017_v_2017.Dec.exp.var.txt

P.S. You need to count the start and end index of the month, e.g. its 1.33,1.36n in your example.

Finding and sorting unique file names regardless of parent folder name

Print the file name with and without its directory, sort -u on just the file name, then remove the file name so only the full path shows.

$ find ~/Parent -name '*.txt' -printf '%f\t%p\n' | sort -k1,1 -u | cut -f 2-
~/Parent/A/a.txt
~/Parent/A/b.txt
~/Parent/C/c.txt
~/Parent/C/d.txt

Note that this will decide conflicts arbitrarily since find prints file names in no particular order. If you want to always use the first or the last duplicate files, add an extra sort or sort -r call:

Always use the first:

$ find ~/Parent -name '*.txt' -printf '%f\t%p\n' | sort    | sort -k1,1 -u | cut -f 2-

Always use the last:

$ find ~/Parent -name '*.txt' -printf '%f\t%p\n' | sort -r | sort -k1,1 -u | cut -f 2-

Bash and sort files in order

ls data_* | sort -n -t _ -k 2

-n: sorts numerically

-t: field separator '_'

-k: sort on second field, in your case the numbers after the first '_'

How to sort files in some directory by the names on Linux

The idiomatic way to sort something in C is to use the qsort() function. For this to work, it's best if you can arrange to have all the file names collected into an array of pointers, and then you sort the array.

This is not too hard, but it does require either a bit of dynamic-array management, or that you introduce static limits on things (maximum length of filenames, maximum number of files).

How can I sort file names by version numbers?

Edit: It turns out that Benoit was sort of on the right track and Roland tipped the balance

You simply need to tell sort to consider only field 2 (add ",2"):

find ... | sort --version-sort --field-separator=- --key=2,2

Original Answer: ignore

If none of your filenames contain spaces between the hyphens, you can try this:

find ... | sed 's/.*-\([^-]*\)-.*/\1 \0/;s/[^0-9] /.&/' | sort --version-sort --field-separator=- --key=2 | sed 's/[^ ]* //'

The first sed command makes the lines look like this (I added "10" to show that the sort is numeric):

1.9.a command-1.9a-setup
2.0.c command-2.0c-setup
2.0.a command-2.0a-setup
2.0 command-2.0-setup
10 command-10-setup

The extra dot makes the letter suffixed version number sort after the version number without the suffix. The second sed command removes the prefixed version number from each line.

There are lots of ways this can fail.



Related Topics



Leave a reply



Submit