Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have a bunch of files from log1 to log164.

I'm trying to LIST the directory (sorted) in a UNIX terminal but the sort functions are only providing the format like this:

home:logs Home$ ls -1 | sort
log1.gz
log10.gz
log100.gz
log101.gz
log102.gz
log103.gz
log104.gz
log105.gz
log106.gz
...etc

What I want is

home:logs Home$ ls -1 | sort
log1.gz
log2.gz
log3.gz
log4.gz
log5.gz
log6.gz
log7.gz
...{more here}
log99.gz
log100.gz
log101.gz
log102.gz
...etc

Any suggestions in what I could use to do this?

share|improve this question
1  
This is absolutely a programming question, and does not deserve to be migrated just because the answer involves the lowly shell programming language!!! –  tchrist Mar 9 '12 at 2:31
    
If you know in advance that they're named log1.gz through log164.gz, then what do you even need to ls -1 them for? –  ruakh Mar 9 '12 at 2:32
    
@ruakh ls -1 displays the results in one column rather then across –  Rabiani Mar 9 '12 at 2:40
1  
@Rabiani: I know what ls -1 does: it lists filenames. Since you already knew the filenames, I didn't understand what you needed it for. But since you've accepted Kevin's answer, I now know: you didn't need it. Which makes more sense. :-) –  ruakh Mar 9 '12 at 2:41
add comment

migrated from stackoverflow.com Mar 10 '12 at 15:05

This question came from our site for professional and enthusiast programmers.

6 Answers

up vote 14 down vote accepted

bash's braces, {}, will enumerate them in order:

for file in log{1..164}.gz; do
    process "$file"
done
share|improve this answer
add comment

My version of Solaris doesn't support ls -v (grrr). And the sort solution provided above 1) requires knowledge of the position of digits in the filename, and 2) doesn't handle things like multi-part version numbers.

The approach below is Solaris-compatible, doesn't require foreknowledge of the digit positions, and handles version numbers with 2, 3 or 4 components (like: a-1.2, foo-5.6.7, bar_baz_9.10.11.12). It also uses sort -f to fold upper- and lowercase together, and properly handles directories intermixed with files:

ls -d | sort -f -t . -k 1,1 -k 2,2n -k 3,3n -k 4,4n

Note that this version limits the first component to a single digit.

If your target operating system(s) supports ls -v, that is clearly the superior solution.

share|improve this answer
add comment

While the solution ls -1v is certainly the nicest in this particular case, I think it's good to have also one that works with sort as in the original question, since this works also when your input does not come from ls. In this case you can use

ls -1 | sort -n -k1.4

The -n option tells sort to sort numerically, and -k 1.4 sets the sort key to the first field (which is the whole filename in this case) starting from the 4th character up to the last.

share|improve this answer
add comment

With GNU ls (i.e. on Linux, Cygwin, or other systems that have GNU ls specifically installed):

ls -v

In zsh:

echo *(on)

In other shells:

echo log?.gz log??.gz log???.gz

Replace echo by printf '%s\n' if you want each file name on a separate line.

If you want file metadata as well (ls -l) and you don't have GNU ls, you'll need to call ls separately for each file name or group of file names that you want to see in lexicographic order.

ls -l log?.gz; ls -l log??.gz; ls -l log???.gz

To avoid these difficulties, use enough leading zeroes in your file names so that the lexicographic sort is human-friendly (log001.gz, etc).

share|improve this answer
add comment

Why not to use built-in ls feature for this particular case, namely

-v natural sort of (version) numbers within text

For example ls -1v log*

share|improve this answer
add comment

Perl solution:

ls log*.gz | perl -ne 'sub getnum{ $_[0] =~ /log(\d+)\.gz/; $1 }; push @A, $_; END{ print sort { getnum $a <=> $b } @A}'
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.