Bash descending filename sorting [duplicate] - linux

This question already has answers here:
Sort files numerically in bash
(3 answers)
Closed 8 years ago.
I've been trying to sort my filenames with commands similar to ls -1 | sort -n -t "_" -k1 but just can't get it to work. Please help.
I have:
10_filename
11_filename
12_filename
1_filename
2_filename
I want to get:
1_filename
2_filename
...
10_filename
11_filename

Please try following this will solve the issue
ls -1v
-v It sorts on basis of file version versions

Try this,
ls -1 *\_filename | sort -n
or
ls -1 | sort -n

ls -1 | sort -t '_' +1 +0n
below, a bit heavy but working if sort does not accept field order and using simple string sort.
ls -1 | sed 's/^\([0-9]*\)_\(.*\)/000\1_\1_\2/;s/^0*\([0-9]\{3\}\)/\1/;s/\([0-9]\{1,\}_[0-9]\{1,\}_\)\(.*\)/\2_\1/' | sort -n | sed 's/\(.*\)_[0-9]\{1,\}_\([0-9]\{1,\}\)_$/\2_\1/'

Related

Bash sort files by filename containing year and abbreviated month [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have files for many years and all months, with example names: dir1/dir2/dir3/file_name_2017_v_2017.Jan.exp.var.txt, dir1/dir2/dir3/file_name_2017_v_2017.Feb.exp.var.txt, …, and dir1/dir2/dir3/file_name_2017_v_2017.Dec.exp.var.txt.
There is a script executing a one line command to store a list of files in an array.
ls dir1/dir2/dir3/file_name_2017_v_*.exp.var.txt
This works, however they are out of order by month. I would like them to be sorted by YYYY.MMM. I have tried various sort commands using -M to lastly sort by month, however nothing is working. What am I missing to sort these files? I prefer a one-line command to sort these.
Edit 1:
Using ls *.txt | sort --field-separator='.' -k 1,2M -r reverses the year order, and the alphabetical order of the months. Removing the -r puts the years in chronological order, however the months are in alphabetical order. This is not what I want, as I want the files in chronological order
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.
Just for fun, this one liner will sort independently of directory names and with a bit of work, also independently of filenames.
First, add year and month as fields at beginning of record and sort by them
find dir1/ -name '*.exp.var.txt' | sed -re 's/^.*_v_(201[5-7])\.([A-Za-z]{3,3})\.exp.var.txt$/\1 \U\2 \E&/' | LC_TIME=en_US sort -k 1n -k 2M
This will return
2015 JAN dir1/dir2/dir3/file_name_2017_v_2015.Jan.exp.var.txt
2015 FEB dir1/dir2/dir3/file_name_2017_v_2015.Feb.exp.var.txt
2015 MAR dir1/dir2/dir3/file_name_2017_v_2015.Mar.exp.var.txt
2015 APR dir1/dir2/dir3/file_name_2017_v_2015.Apr.exp.var.txt
2015 MAY dir1/dir2/dir3/file_name_2017_v_2015.May.exp.var.txt
Then, just print the needed field
find dir1/ -name '*.exp.var.txt' | \
sed -re 's/^.*_v_(201[5-7])\.([A-Za-z]{3,3})\.exp.var.txt$/\1 \U\2 \E&/' | \
LC_TIME=en_US sort -k 1n -k 2M | \
gawk '{ print $3 }'
Result:
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

How to get the second latest file in a folder in Linux

Found several posts like this one to tell how to find the latest file inside of a folder.
My question is one step forward, how to find the second latest file inside the same folder? The purpose is that I am looking for a way to diff the latest log with a previous log so as to know what have been changed. The log was generated in a daily basis.
Building on the linked solutions, you can just make tail keep the last two files, and then pass the result through head to keep the first one of those:
ls -Art | tail -n 2 | head -n 1
To do diff of the last (lately modified) two files:
ls -t | head -n 2 | xargs diff
Here's a stat-based solution (tested on linux)
for x in ./*;
do
if [[ -f "$x" ]]; then
stat --printf="%n %Y\n" "$x"; fi;
done |
sort -k2,2 -n -r |
sed -n '2{p;q}'
ls -dt {{your file pattern}} | head -n 2 | tail -n 1
Will provide second latest file in the pattern you search.
Here's the command returns you latest second file in the folder
ls -lt | tail -n 1 | head -n 2
enjoy...!

How to catch duplicate entries in text file in linux [duplicate]

This question already has answers here:
How to delete duplicate lines in a file without sorting it in Unix
(9 answers)
Closed 4 years ago.
Text file:
1 1
2 2
3 3
1 1
I want to catch 1 1 as duplicated
Your question is not quite clear, but you can filter out duplicate lines with uniq:
sort file.txt | uniq
or simply
sort -u file.txt
(thanks RobEarl)
You can also print only repeating lines with
sort file.txt | uniq -d
One way using GNU awk:
awk 'array[$0]++' file.txt
Results:
1 1
You can use it easily:
sort -u file.txt
OR
awk '!x[$0]++' file.txt

first two results from ls command

I am using ls -l -t to get a list of files in a directory ordered by time.
I would like to limit the search result to the top 2 files in the list.
Is this possible?
I've tried with grep and I struggled.
You can pipe it into head:
ls -l -t | head -3
Will give you top 3 lines (2 files and the total).
This will just give you the first 2 lines of files, skipping the size line:
ls -l -t | tail -n +2 | head -2
tail strips the first line, then head outputs the next 2 lines.
To avoid dealing with the top output line you can reverse the sort and get the last two lines
ls -ltr | tail -2
This is pretty safe, but depending what you'll do with those two file entries after you find them, you should read Parsing ls on the problems with using ls to get files and file information.
Or you could try just this
ls -1 -t | head -2
The -1 switch skips the title line.
You can use the head command to grab only the first two lines of output:
ls -l -t | head -2
You have to pipe through head.
ls -l -t | head -n 3
will output the two first results.
Try this:
ls -td -- * | head -n 2

How can I print intermediate results from a pipeline to the screen? [duplicate]

This question already has answers here:
How can I gzip standard in to a file and also print standard in to standard out?
(4 answers)
Closed 7 years ago.
I'm trying to count the lines from a command and I'd also like to see the lines as they go by. My initial thought was to use the tee command:
complicated_command | tee - | wc -l
But that simply doubles the line count using GNU tee or copies output to a file named - on Solaris.
complicated_command | tee /dev/tty | wc -l
But keep in mind that if you put it in a script and redirect the output, it won't do what you expect.
The solution is to tee to the console directly as opposed to STDOUT:
tty=`tty`
complicated_command | tee $tty | wc -l

Resources