I have a directory that contains
frame0.png
frame1.png
frame2.png
...
frame20.png
I want to use wildcards such that ls -l shows me the files ordered by the number. I tried
ls -l frame?.png frame??.png
because I thought it would first seach for the items with just one digit, order them and then do the same with two digits but, the output is
frame0.png
frame10.png
frame11.png
...
frame1.png
frame20.png
frame2.png
...
frame9.png
How can I circumvent that bash orders them like that?
If you have gnu utilities then use -v option to get natural sort:
ls -lv frame*.png
If you don't have gnu ls then try this find + sort:
find . -maxdepth 1 -name 'frame*.png' | sort -V
Related
I have an assignment where, only using bash one-liners, I must ls the specific directories in my home directory that do not follow a specific naming schema. In my home directory, there are some directories that have the format of 3 alphabetical lower case letters followed by 3 decimal digits. However, there are other directories that don't follow this format. I must list those files and output the info to a txt file. Here are some commands I have written so far and am experimenting with:
ls /home -1 | sed [^a-z][^a-z][^a-z].[^0-9][^0-9][^0-9]
ls /home -1 "[^[a-z][a-z][a-z][0-9][0-9][0-9]]"
ls /home -1 *{[^a-z][^a-z][^a-z].[^0-9][^0-9][^0-9]}*
Also before anyone asks, I know formatting and searching through the output of the ls command is not as effective as the find command. But the assignment that I am working on dictates that I may only use these commands: ls, ps, sed, cut, paste, sort, tr, grep, awk, cat, uniq
If you can use shopt -s extglob first, then
ls -1d /home/!([a-z][a-z][a-z][0-9][0-9][0-9])
If not,
ls -1d /home/* | grep -v '/home/[a-z][a-z][a-z][0-9][0-9][0-9]$'
PLEASE read the manual pages for ls, grep, and shopt.
If you don't understand why these work, you haven't learned anything, and we're just doing your work for you...
The result of my find command produces the following result
./alex20_0
./alex20_1
./alex20_2
./alex20_3
I saved this result as a variable. now the only part I really need is whatever the last part is or essentially the highest number or "latest version".
So from the above string all I need to extract is ./alex20_3 and save that as a variable. Is there a way to just extract whatever the last directory is outputted from the find command?
I would do the last nth characters command to extract it since its already in order, but it wouldn't be the same number of characters once we get to version ./alex20_10 etc.
Try this:
your_find_command | tail -n 1
find can list your files in any order. To extract the latest version you have to sort the output of find. The safest way to do this is
find . -maxdepth 1 -name "string" -print0 | sort -zV | tail -zn1
If your implementation of sort or tail does not support -z and you are sure that the filenames are free of line-breaks you can also use
find . -maxdepth 1 -name "string" -print | sort -V | tail -n1
There could be multiple ways to achieve this -
Using the 'tail' command (as suggested by #Roadowl)
find branches -name alex* | tail -n1
Using the 'awk' command
find branches -name alex* | awk 'END{print}'
Using the 'sed' command
find branches -name alex* | sed -e '$!d'
Other possible options are to use a bash script, perl or any other language. You best bet would be the one that you find is more convenient.
Since you want the file name sorted by the highest version, you can try as follows
$ ls
alex20_0 alex20_1 alex20_2 alex20_3
$ find . -iname "*alex*" -print | sort | tail -n 1
./alex20_3
I am not that experienced with bash and I have a question.
I am trying to select some files (let's say ls for this example) that do not match a certain array o patterns.
I have files named Test,Test1,Test2,Test3,Test4,Test5,Test6,Test7,Test8,Test9,Test10 that I need to select in two groups.
1st group is Test5,Test6,Test7,Test8,Test9,Test10 which I can list by using:
ls -l T*#(5|6|7|8|9|10) or ls -l T*{5,6,7,8,9,10}
The 2nd group is the tricky one (for me) because of the Test & Test1 files. I am trying to invert the previous selection/listing.. or somehow select the rest.
I have tried several things with no luck:
ls -l T*[!5678910]
ls -l T*[!#(5|6|7|8|9|10)]
ls -l T*[!5][!6][!7][!8][!9][!10]
ls -l T*#(1|2|3|4|)
p.s: the actual filenames have extra characters after the number.
You can inverse a pattern like this:
# enable extended glob, if disabled, it will not function
shopt -s extglob
# create our files
touch {Test,Test1,Test2,Test3,Test4,Test5,Test6,Test7,Test8,Test9,Test10}
# list files with matching pattern
ls -1 T*#(5|6|7|8|9|10)
Test10
Test5
Test6
Test7
Test8
Test9
# list files with NOT matching pattern
ls -1 T!(*#(5|6|7|8|9|10))
Test
Test1
Test2
Test3
Test4
You may use an empty string as an option in the list:
ls -l Test*{,1,2,3,4}
[EDIT] But in general I don't see a way to do inverted match in bash alone. Also I see now that there may be other characters after numbers (I suppose non-numerical, or you would have no way to distinguish). I would use ´grep´ , possibly with ´-v´ flag for negation.
ls -1 | grep -v "Test\(\(5\)\|\(6\)\|\(7\)\|\(8\)\\|\(9\)\|\(10\)\)"
I'm not sure why it doesn't work with *, but it works with more specific patterns:
ls -l Test#(1|2|3|4|)
ls -l Test?([1-4])
ls -l T+([^0-9])?([1-4])
If ls is not your only acceptable command, you can also use find with regex to achieve your purpose:
Create all test files:
touch Test{,1,2,3,4,5,6,7,8,9,10}
Find your 1st group of files with regex:
find -type f -regex "\./Test\([5-9]\|10\)"
Reverse is simple, just add a ! before option -regex:
find -type f ! -regex "\./Test\([5-9]\|10\)"
It works on Linux Bash.
I have a script that creates files with output_#.root where # is a number. When I do ls in the directory, it chooses to order the files in a weird way:
output_1.root
output_10.root
output_100.root
output_11.root
output_2.root
etc.
How do I make it order the files in the logical order 1, 2, 3, etc.
Your files are sorted by alphabetical order. It's normal behavior. If you want to sort them by numerical order, you can try this:
ls *.root | sort -k2 -t_ -n
This will split your result using _ as a separator, and order by numerical order -n based on the second field -k2.
If you are using ls from GNU coreutils you can use the version-sort switch:
ls -v
Create example files:
touch output_1.root output_10.root output_100.root output_11.root output_2.root
List them:
ls -1v
Output:
output_1.root
output_2.root
output_10.root
output_11.root
output_100.root
I want to find and count all the files on my system that begin with some string, say "foo", using only one line in bash.
I'm new to bash so I'd like to avoid scripting if possible - how can I do this using only simple bash commands and maybe piping in just one line?
So far I've been using find / -name foo*. This returns the list of files, but I don't know what to add to actually count the files.
You can use
find / -type f -name 'foo*' | wc -l
Use the single-quotes to prevent the shell from expanding the asterisk.
Use -type f to include only files (not links or directories).
wc -l means "word count, lines only." Since find will list one file per line, this returns the number of files it found.
find / -name foo* | wc -l should do it. Here is a link to man wc. wc -l counts the number of lines
You can pipe it into wc
find / -name foo * | wc -l