Linux - NewbieThis Linux forum is for members that are new to Linux.
Just starting out and have a question?
If it is not in the man pages or the how-to's this is the place!
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
yes, the correct answer is #4, move the files into another directory and move them back in the desired order. ls will sort alphabetically by default - it is obvious, the real order of the files is not arranged by the filesystem. It simply stores the entries. You can check it by ls -U, see the man page.
What you need is to sort those entries as numbers. ls cannot do it, so you need to pipe the result across sort. See the man page to find out how can you make a numeric sort.
_____________________________________
If someone helps you, or you approve of what's posted, click the "Add to Reputation" button, on the left of the post.
Happy with solution ... mark as SOLVED
(located in the "thread tools")
first, the "order in the directory" has no real meaning---the files are in random location based on the order in which they were created and where the file system found available space. I think you mean to say---"the order in which they are listed".
If the filenames all have numbers at the front, then it appears that this works: ls |sort -n
but this simple solution will not work with ls -l
It might help to know why you want to do this---what problem are you trying to solve?
I assembled this script because this is a problem which I seldom encounter too, so I thought it was time to put together a reusable solution.
The script should be called from within the directory containing the files to be renamed. It can accept an optional argument which is a hint to at how many digits you want your numbers to be padded to; it's a hint because the script already computes the minimum required length to correctly pad all the files contained in the directory and uses the user supplied value only if it's greater than the computed value.
It's also possible to go back to a minimum padding if the user previously used an unnecessarily high argument. BIG PHAT WARNING: i tested the script on a bunch of automatically generated files so, before using this script to alter real-world files, please backup your data.
Code:
#!/bin/sh
# 0 pad filenames starting with a number in the current directory
# Copyright 2012 Alan Alberghini <414N@slacky.it>
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# This script renames a bunch of files in the current directory matching
# FILE_PATTERN adding prepending 0s to their numbers in order to see them
# sorted in directory listings etc.
# Script arguments:
# $1 - (OPTIONAL) number of digits that the number inside the filename should
# have. It's used only if its value is greater than the value
# automatically computed from the number of files in the directory.
# The regex corresponding to the files to be renamed.
FILE_PATTERN='^[0-9]+'
# Function rename_file
# Renames the given file with the correct 0-padding
# Arguments:
# $1 - filename of the file to rename
function rename_file()
{
# Extract the number part from the filename using FILE_PATTERN
NUMBER=`echo "$1" | egrep -o $FILE_PATTERN`
# Extract the number of significant digits
NUMBER_TRIMMED=$(seq $NUMBER $NUMBER)
# Store the remainder of the file name
FILE_REMAINDER="`echo "$1" | sed -e "s|$NUMBER||"`"
# If the extracted NUMBER has less significant digits than NUM_DIGITS,
# the file is renamed.
if [ ${#NUMBER_TRIMMED} -le $NUM_DIGITS ]
then
mv "$1" `printf %0${NUM_DIGITS}d $(( 10#$NUMBER ))`"$FILE_REMAINDER"
fi
}
# This variable contains the number of 0s wanted by the user, or 0 if not
# specified
NUM_ZERO_USR=${1:-0}
# The modified regex for find. find expects a regex string matching the entire
# path, so, for searching in current directory, './' has to be prepended to
# the pattern string, as '.*' has to be appended to match the rest of the
# filename
FIND_FILE_PATTERN=`echo $FILE_PATTERN | sed -e 's|\^|\^./|'`'.*'
# The find command which will be used hereon.
FIND_BASECOMMAND="find . -type f -maxdepth 1 -regex $FIND_FILE_PATTERN"
# The number of files that need to be renamed. We only look to files matching
# FILE_PATTERN
NUM_FILES=`$FIND_BASECOMMAND | wc -l`
# Compute the number of digits needed to count every file. It is done as:
# Ceiling(Log(10, NUM_FILES))
# where:
# Ceiling is the function which returns the minum integer which is greater than its argument;
# Log(10, NUM_FILES) is the logarithm to base 10 of NUM_FILES
# Given that bc lacks a ceiling function, we discard the decimal part of the
# result and then add 1 to it.
NUM_DIGITS_NEEDED=$((`echo "l($NUM_FILES)/l(10)" | bc -l | cut -d. -f1`+1))
# If the number of digits specified by the user is greater than what has been
# extracted from the number of files, then we'll use the user value hereon.
if [ $NUM_ZERO_USR -gt $NUM_DIGITS_NEEDED ]
then
NUM_DIGITS=$NUM_ZERO_USR
else
NUM_DIGITS=$NUM_DIGITS_NEEDED
fi
echo "Going to rename $NUM_FILES files, padding numbers to $NUM_DIGITS inside current directory ."
$FIND_BASECOMMAND -exec basename {} \; | while read FILE; do rename_file "$FILE"; done
I also have a script that pads numbers in filenames.
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}" #set the COLOR variable below to the desired one
#BBLUE="${BBLUE:-\e[1;34m}"
#BMAGENTA="${BMAGENTA:-\e[1;35m}"
RESET="${RESET:-\e[0m}"
COLOR=$BCYAN #choose which color to use here
#set default padding level
pad=2
# Set up the help dialog
help(){
local -a help
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${COLOR}${0##*/} [-n <num>] <files>${RESET}" )
help+=( "\t\t${COLOR}${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+=( '' )
help+=( '\t-h prints this help message' )
help+=( '' )
local IFS=$'\n'
echo -e "${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) help >&2
exit "2"
;;
n) if [[ "$OPTARG" =~ [^[:digit:]] ]] || (( "10#$OPTARG" < 1 )) || (( "10#$OPTARG" > 9 )); then
echo
echo -e "${COLOR}invalid option: [$OPTARG].${RESET}" >&2
echo -e "${COLOR}-n must be an integer from 1 to 9${RESET}" >&2
echo -e "${COLOR}Falling back to the default of $pad${RESET}"
echo
else
pad="$(( 10#$OPTARG ))"
fi
;;
\?) echo -e "${COLOR}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
re='([^[0-9]*)([0-9]+)(.*)'
for file ; do
# Ignore files without digits
[[ "$file" != *[0-9]* ]] && continue
# Split filename into prefix-digits-suffix
[[ "$file" =~ $re ]]
# 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 "${COLOR}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*) for i in "${!oldfile[@]}" ; do
mv -n "${oldfile[i]}" "${newfile[i]}"
done
echo
;;
*) echo -e "${COLOR}Aborting.${RESET}"
echo
exit 1
;;
esac
# Otherwise just exit.
else
echo
echo -e "${COLOR}No files to rename.${RESET}" >&2
echo -e "${COLOR}Exiting.${RESET}" >&2
echo
exit 1
fi
exit 0
One advantage of mine is that you can pass it a list of files to work on, instead of just the directory. And if you use "-n 1", it will remove all zero-padding. On the other hand, it only operates on the first number string in the filename at this point.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.