Skip to main content
Clarification
Source Link
Chris Davies
  • 128.1k
  • 16
  • 179
  • 324

This sorts by prepending the file pathnames with the basename, sorting that numerically, and then stripping the basename from the front of the string:

#!/bin/bash
#
filearray=("dir1/0010.pdf" "dir2/0003.pdf" "dir3/0040.pdf" "dir4/0003.pdf")

sortarray=($(
    for file in "${filearray[@]}"
    do
        echo "$file"
    done |
        sed -r 's!^(.*)/([[:digit:]]*)(.*)$!\2 \1/\2\3!' |
        sort -t $'\t' -n |
        sed -r 's![^ ]* !!'
))

for item in "${sortarray[@]}"
do
    echo "> $item <"
done

It would be more efficient if you had the filenames in a list that could be passed directly through a pipe rather than as a shell array, because the actual work is done by the sed | sort | sed structure, but this suffices.

I first came across this technique when coding in Perl; in that language it was known as a Schwartzian Transform.

In Bash the transform as given here in my code will fail if you have non-numerics in the file's basename. In Perl it could be coded far more safely.

This sorts by prepending the file pathnames with the basename, sorting that numerically, and then stripping the basename from the front of the string:

#!/bin/bash
#
filearray=("dir1/0010.pdf" "dir2/0003.pdf" "dir3/0040.pdf" "dir4/0003.pdf")

sortarray=($(
    for file in "${filearray[@]}"
    do
        echo "$file"
    done |
        sed -r 's!^(.*)/([[:digit:]]*)(.*)$!\2 \1/\2\3!' |
        sort -t $'\t' -n |
        sed -r 's![^ ]* !!'
))

for item in "${sortarray[@]}"
do
    echo "> $item <"
done

It would be more efficient if you had the filenames in a list rather than a shell array, because the actual work is done by the sed | sort | sed structure, but this suffices.

I first came across this technique when coding in Perl; in that language it was known as a Schwartzian Transform.

In Bash the transform as given here in my code will fail if you have non-numerics in the file's basename. In Perl it could be coded far more safely.

This sorts by prepending the file pathnames with the basename, sorting that numerically, and then stripping the basename from the front of the string:

#!/bin/bash
#
filearray=("dir1/0010.pdf" "dir2/0003.pdf" "dir3/0040.pdf" "dir4/0003.pdf")

sortarray=($(
    for file in "${filearray[@]}"
    do
        echo "$file"
    done |
        sed -r 's!^(.*)/([[:digit:]]*)(.*)$!\2 \1/\2\3!' |
        sort -t $'\t' -n |
        sed -r 's![^ ]* !!'
))

for item in "${sortarray[@]}"
do
    echo "> $item <"
done

It would be more efficient if you had the filenames in a list that could be passed directly through a pipe rather than as a shell array, because the actual work is done by the sed | sort | sed structure, but this suffices.

I first came across this technique when coding in Perl; in that language it was known as a Schwartzian Transform.

In Bash the transform as given here in my code will fail if you have non-numerics in the file's basename. In Perl it could be coded far more safely.

Source Link
Chris Davies
  • 128.1k
  • 16
  • 179
  • 324

This sorts by prepending the file pathnames with the basename, sorting that numerically, and then stripping the basename from the front of the string:

#!/bin/bash
#
filearray=("dir1/0010.pdf" "dir2/0003.pdf" "dir3/0040.pdf" "dir4/0003.pdf")

sortarray=($(
    for file in "${filearray[@]}"
    do
        echo "$file"
    done |
        sed -r 's!^(.*)/([[:digit:]]*)(.*)$!\2 \1/\2\3!' |
        sort -t $'\t' -n |
        sed -r 's![^ ]* !!'
))

for item in "${sortarray[@]}"
do
    echo "> $item <"
done

It would be more efficient if you had the filenames in a list rather than a shell array, because the actual work is done by the sed | sort | sed structure, but this suffices.

I first came across this technique when coding in Perl; in that language it was known as a Schwartzian Transform.

In Bash the transform as given here in my code will fail if you have non-numerics in the file's basename. In Perl it could be coded far more safely.