LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Ubuntu (https://www.linuxquestions.org/questions/ubuntu-63/)
-   -   Finding max number in filename and opening it (https://www.linuxquestions.org/questions/ubuntu-63/finding-max-number-in-filename-and-opening-it-920431/)

rpd25 12-25-2011 02:30 AM

Finding max number in filename and opening it
 
Hi,

I have files named as

energy.dat.1
energy.dat.2
energy.dat.3
...
energy.dat.2342

I would like to find the file with maximum number in the filename (ex. energy.dat.2342), select it and read the numeric content in scilab/octave/python for plotting.

Would you please share your expertize in writing the script?

Thanks in advance.

jv2112 12-25-2011 05:25 AM

This will give you the file count so a s long as you know the starting # and the naming convention is consisten then you will know the last file name.

:twocents:

Code:

find /path/to/where/you/want_to/look/ -iname *.dat.*[0-9] | wc -l
Hope this Helps. ;)

colucix 12-25-2011 07:49 AM

Two alternatives using numerical sorting and numerical comparison respectively:
Code:

ls energy.dat.* | sort -t. -k3n | tail -1
Code:

ls energy.dat.* | awk -F. '{if ( num<$3 ){num = $3; file = $0}}END{print file}'

druuna 12-25-2011 08:06 AM

Hi,

Another alternative:
Code:

ls -1v | tail -1
That's a 1 (one) not an l (el).

Hope this helps.

colucix 12-25-2011 08:13 AM

Nice one, druuna! I didn't know about the -v option.

druuna 12-25-2011 08:53 AM

Quote:

Originally Posted by colucix (Post 4558018)
Nice one, druuna! I didn't know about the -v option.

I have my moments :D

David the H. 12-25-2011 09:44 AM

As a in-shell solution, you can loop through filenames, and search and print out the one with the largest number. In bash:

Code:

last=0
for file in energy.dat.[0-9]* ; do
        (( ${file//[^0-9]} > ${last//[^0-9]} )) && last=$file
done

echo "$last"

This example assumes that there's only a single set of non-zero-padded* digits in each files, as ${file//[^0-9]} simply removes everything else. But it should be easily modifiable for other patterns.

(*most shells treat integers with leading zeros as octal values when doing arithmetic operations. )

Speaking of zero-padding, the real best way to handle it, in my opinion, is to simply make sure all the numbers are zero-padded to the same number of digits first. Then the shell will sort them for you automatically, and you can simply use whichever technique you want to grab the last value in the list.

Add all the names to an array, for example, and use the final entry.

Code:

files=( energy.dat.[0-9]* )

echo "${files[-1]}"        #bash 4.2+ allows negative indexing
echo "${files[@]: -1}"        #for earlier versions

I wrote this script a while ago that zero-pads numbers in file names. You can give it a try.

Code:

#!/bin/bash

# Pads numbers in file names if found.
# See help message for more.

# Set the environment
shopt -s extglob
IFS=""

BCYAN="${BCYAN:-\e[1;36m}"    #Define some color codes, for prettified output.
#BGREEN="${BGREEN:-\e[1;32m}"  #Use environment defaults if they exist.
#BRED="${BRED:-\e[1;31m}"
#BBLUE="${BBLUE:-\e[1;34m}"
#BMAGENTA="${BMAGENTA:-\e[1;35m}"
RESET="${RESET:-\e[0m}"

#set default padding level
pad=2


# Set up the help dialog
help+=( ''                                                                                                                                                                )
help+=( '\tA quick script to zero-pad files that contain numbers.'                                                                        )
help+=( '\tIt will only pad the first number string it finds in the name, and ignores files without numbers.'        )
help+=( ''                                                                                                                                                                )
help+=( "\tUsage: \t${BCYAN}${0##*/} [-n <num>] <files>${RESET}"                                                                                )
help+=( "\t\t${BCYAN}${0##*/} -h${RESET}"                                                                                                                )
help+=( ''                                                                                                                                                                )
help+=( '\tUse -n to specify the number of digits to pad, from 1-9.  Defaults to '"$pad"' if not used.'                )
help+=( '\tIf no files are given, it processes the current directory.'                                                                )
help+=( ''                                                                                                                                                                )


# Process input options
# If "-h" print help & exit.
# If "-n" test for valid inputs and set "pad" variable
# Ignore anything else
while getopts ":hn:" opt; do

    case "$opt" in

          h) IFS=$'\n'
                  echo -e "${help[*]}" >&2
            exit "2"
          ;;

          n)        if [[ "$OPTARG" =~ [^[:digit:]] ]] || (( "10#$OPTARG" < 1 )) || (( "10#$OPTARG" > 9 )); then
                                echo
                                echo -e "${BCYAN}invalid option: [$OPTARG].${RESET}" >&2
                                echo -e "${BCYAN}-n must be an integer from 1 to 9${RESET}" >&2
                                echo -e "${BCYAN}Falling back to the default of $pad${RESET}"
                                echo
                        else
                                pad="$(( 10#$OPTARG ))"
                        fi
          ;;

          \?) echo -e "${BCYAN}Invalid option: [-$OPTARG].  Ignoring.${RESET}" >&2
          ;;
    esac
done

shift $(( OPTIND - 1 )) ; OPTIND=1

# Now test for files.
# If nothing given, set input parameters to files in current directory.
if [[ -z "$*" ]]; then
        set -- ./*
fi

# Process files in input parameters
for file in "$@" ; do

        # Ignore files without digits
        [[ "$file" != *[0-9]* ]] && continue

        # Split filename into prefix-digits-suffix
        [[ "$file" =~ ([^[0-9]*)([0-9]+)(.*) ]]

        # Pad digits to desired width
        printf -v numpad "%0*d" "$pad" "${BASH_REMATCH[2]##*(0)}"

        # Add old and new filenames to arrays for final processing
        oldfile+=( "$file" )
        newfile+=( "${BASH_REMATCH[1]}${numpad}${BASH_REMATCH[3]}" )

done

# If there are any files to rename, ask to confirm the operation.
# And rename if confirmed.
if [[ -n "${oldfile[*]}" ]]; then

        echo
        echo -e "${BCYAN}Rename the following files?${RESET}"
        echo
        for i in "${!oldfile[@]}" ; do
                echo -e "${oldfile[i]/#$PWD/.}\t-->\t${newfile[i]/#$PWD/.}"
        done
        echo

        read -p "(y/n): "

        echo

        case "$REPLY" in

                y|Y*)          for i in "${!oldfile[@]}" ; do
                                        mv -n "${oldfile[i]}" "${newfile[i]}"
                                done
                                echo
                                ;;

                *)                echo -e "${BCYAN}Aborting.${RESET}"
                                echo
                                exit 1
                                ;;
        esac

# Otherwise just exit.
else
        echo
        echo -e "${BCYAN}No files to rename.${RESET}" >&2
        echo -e "${BCYAN}Exiting.${RESET}" >&2
        echo
        exit 1

fi

exit 0



All times are GMT -5. The time now is 12:24 AM.