0

Can't boot my Windows PC today and I am on 2nd OS Linux Mint. With my limited knowledge on Linux and shell scripts, I really don't have an idea how to do this.

I have a bunch of files in a directory generated from my system, need to remove the last 12 characters from the left of ".txt"

Sample filenames:

filename1--2c4wRK77Wk.txt
filename2-2ZUX3j6WLiQ.txt
filename3-8MJT42wEGqQ.txt
filename4-sQ5Q1-l3ozU.txt
filename5--Way7CDEyAI.txt

Desired result:

filename1.txt
filename2.txt
filename3.txt
filename4.txt
filename5.txt

Any help would be greatly appreciated.

htan68
  • 33
  • 2
  • 6

2 Answers2

0

Here is a programmatic way of doing this while still trying to account for pesky edge cases:

#!/bin/sh
set -e

find . -name "filename*" > /tmp/filenames.list

while read -r FILENAME; do
    NEW_FILENAME="$(
        echo "$FILENAME" | \
            awk -F '.' '{$NF=""; gsub(/ /, "", $0); print}' | \
            awk -F '/' '{print $NF}' | \
            awk -F '-' '{print $1}'
    )"

    EXTENSION="$(echo "$FILENAME" | awk -F '.' '{print $NF}')"

    if [[ "$EXTENSION" == "backup" ]]; then 
        continue
    else
        cp "$FILENAME" "${FILENAME}.backup"
    fi

    if [[ -z "$EXTENSION" ]]; then
        mv "$FILENAME" "$NEW_FILENAME"
    else
        mv "$FILENAME" "${NEW_FILENAME}.${EXTENSION}"
    fi
done < /tmp/filenames.list

Create a List of Files to Edit

First up create a list of files that you would like to edit (assuming that they all start with filename) and under the current working directory (.):

find . -name "filename*" > /tmp/filenames.list

If they don't start with filename fret not you could always use a find command like:

find . -type f > /tmp/filenames.list

Iterate over a list of files

To accomplish this we use a while read loop:

while read -r LINE; do
    # perform action
done < file

If you had the ability to use bash you could always use a named pipe redirect:

while read -r LINE; do
    # perform action
done < <(
    find . -type f
)

Create a rename variable


Next, we create a variable NEW_FILENAME and using awk we strip off the file extension and any trailing spaces using:

awk -F '.' '{$NF=""; gsub(/ /, "", $0); print}'

We could just use the following though if you know for certain that there aren't multiple periods in the filename:

awk -F '.' '{print $1}'

The leading ./ is stripped off via

awk -F '/' '{print $NF}'

although this could have been easily done via basename


With the following command, we strip everything after the first -:

awk -F '-' '{print $1}'

Creating backups

Feel free to remove this if you deem unnecessary:

if [[ "$EXTENSION" == "backup" ]]; then 
    continue
else
    cp "$FILENAME" "${FILENAME}.backup"
fi

One thing that we definitely don't want is to make backups of backups. The above logic accounts for this.

Renaming the files

One thing that we don't want to do is append a period to a filename that doesn't have an extension. This accounts for that.

if [[ -z "$EXTENSION" ]]; then
    mv "$FILENAME" "$NEW_FILENAME"
else
    mv "$FILENAME" "${NEW_FILENAME}.${EXTENSION}"
fi

Other things of note

  • Odds are that your Linux Mint installation has a bash shell so you could simplify some of these commands. For instance, you could use variable substitution: echo "$FILENAME" | awk -F '.' '{print $NF}' would become "${FILENAME##.*}"

  • [[ is not defined in POSIX sh so you will likely just need to replace [[ with [, but review this document first: https://mywiki.wooledge.org/BashFAQ/031

Robert J
  • 840
  • 10
  • 20
0

From the pattern of filenames it looks like that the first token can be picked before "-" from filenames. Use following command to rename these files after changing directory to where files are located -

for srcFile in `ls -1`; do fileN=`echo $srcFile | cut -d"-" -f1`; targetFile="$fileN.txt"; mv $srcFile $targetFile; done

If above observation is wrong, following command can be used to remove exactly 12 characters before .txt (4 chars) -

for srcFile in `ls -1`; do fileN=`echo $srcFile | rev | cut -c17- | rev`; targetFile="$fileN.txt"; mv $srcFile $targetFile; done

In ls -1, a pattern can be added to filter files from current directory if that is required.

Ajay Srivastava
  • 1,151
  • 11
  • 15