PPGoodMan
PPGoodMan

Reputation: 351

getting the last field of a string separated by a particular delimiter in bash

I'm writing a script that copies a set of files to a directory using bash scripting. A file that I'm trying to copy might already exist in the directory so I have to rename the file to avoid replacing the original one.

For an example if I have to copy a file called "abc.dd.java" and a file with the same name already exists, I have to rename the file as "abc.dd1.java" and copy it.

If the destination contains "abc.dd.java" and "abc.dd1.java" then the file should be renamed "abc.dd2.java"

I wrote a code snippet that does that:

#$file contains the full path for the original file.
#$path contains the full path for the copied file.

copypath="$path"
echo "$path"
count=1
while [ -f "$path" ]
do
    part1=`echo "$copypath" | awk 'BEGIN{FS="."}{for(i=1;i<NF-1;i++){printf("%s.",$i)}printf("%s",$(NF-1))}END{}'`
    part2=`echo "$copypath" | awk 'BEGIN{FS="."}{printf("%s",$NF)}END{}'`
    path="$part1""$count.""$part2"
    count=`expr "$count" + 1`
done
cp "$file" "$path"

This does work correctly. But it seems too crude. Isn't there a better way of separating out the file extension part and the name parts?

Thanks in advance

Upvotes: 0

Views: 76

Answers (3)

tom
tom

Reputation: 22949

A similar question has been answered in Extract filename and extension in bash.

Here is a simple version which (mostly) works, based on that link:

part1="${copypath%.*}"            # remove file extension (shortest .* suffix)
part2="${copypath##*.}"           # remove base path (longest *. prefix)
path="${part1}${count}.${part2}"

And here is a more complete answer which also handles files without extensions:

if [[ "$copypath" =~ [^/.][.][^/.]+$ ]]
then
    # copypath has an extension
    part1="${copypath%.*}"
    part2=".${copypath##*.}"
else
    # no valid extension, so insert the number at the end
    part1="$copypath"
    part2=""
fi
path="${part1}${count}${part2}"

Features:

  • Whitespace is handled well.
  • Multiple dots are handled as requested.
    e.g. abc.dd.java becomes abc.dd1.java
  • Files without an extension are handled properly.
    e.g. file becomes file1
  • Dot files with no extension are also handled properly.
    e.g. .bashrc becomes .bashrc1

Caveats:

  • Multiple extensions are not handled specially.
    e.g. archive.tar.gz becomes archive.tar1.gz instead of archive1.tar.gz
  • If the part before the extension ends with a dot it is not considered to be an extension.
    e.g. This is a sentence..txt becomes This is a sentence..txt2
    To treat this as having an extension change the regular expression to [^/][.][^/.]+$
  • Does not attempt to handle directories.
  • Only tested in Bash, unlikely to work with other shells (but could be changed to use grep).

Upvotes: 1

Ram
Ram

Reputation: 1115

To Split the filename and extention you can use the below string manipulations

filename="/tmp/example.txt"

# will output "txt" (extention)
echo ${filename##*.} 

# will output "/tmp/example" 
echo ${filename%%.*} 

Upvotes: 2

SMA
SMA

Reputation: 37023

Try if you have just .java files with something:

fname=$(basename file.java .java)
echo $fname

output:

file

and then you can do your further processing.

Upvotes: 0

Related Questions