Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Bash, how to convert number list into ranges of numbers?

Currently I have a sorted output of numbers from a command:

18,19,62,161,162,163,165

I would like to condense these number lists into a list of single numbers or ranges of numbers

18-19,62,161-163,165

I thought about trying to sort through the array in bash and read the next number to see if it is +1... I have a PHP function that does essentially the same thing, but I'm having trouble transposing it to Bash:

foreach ($missing as $key => $tag) {
    $next = $missing[$key+1];
    if (!isset($first)) {
        $first = $tag;
    }
    if($next != $tag + 1) {
        if($first == $tag) {
            echo '<tr><td>'.$tag.'</td></tr>';
        } else {
            echo '<tr><td>'.$first.'-'.$tag.'</td></tr>';
        }
        unset($first);
    }
}

I'm thinking there's probably a one-liner in bash that could do this but my Googling is coming up short....

UPDATE: Thank you @Karoly Horvath for a quick answer which I used to finish my project. I'd sure be interested in any simpler solutions out there.

like image 273
jjclarkson Avatar asked Dec 04 '12 17:12

jjclarkson


People also ask

How do you create a range in Bash?

You can iterate the sequence of numbers in bash in two ways. One is by using the seq command, and another is by specifying the range in for loop. In the seq command, the sequence starts from one, the number increments by one in each step, and print each number in each line up to the upper limit by default.

How do you give a range command in Linux?

file [range]* With the help of this command you can specify a range of the alphabets for the files you want. It will list out only those files which starts from the alphabets present in the range.

What is SEQ in bash?

The Bash sequence expression allows you to generate a range of integers or characters.


1 Answers

Yes, shell does variable substitution, if prev is not set, that line becomes:

if [ -ne $n+1] 

Here is a working version:

numbers="18,19,62,161,162,163,165"

echo $numbers, | sed "s/,/\n/g" | while read num; do
    if [[ -z $first ]]; then
        first=$num; last=$num; continue;
    fi
    if [[ num -ne $((last + 1)) ]]; then
        if [[ first -eq last ]]; then echo $first; else echo $first-$last; fi
        first=$num; last=$num
    else
        : $((last++))
    fi
done | paste -sd ","

18-19,62,161-163,165
like image 129
Karoly Horvath Avatar answered Sep 30 '22 10:09

Karoly Horvath