Question: I'm trying to set a variable in an sh script to the last 3 characters of the base name of a file (by base name I mean without the path *and* without the suffix). I've succeeded in doing this but, purely out of curiosity, I'm wondering if there is a shorter, single command I can use. Originally I had a one-liner with `awk`, but it was rather long. Currently I have this two-line script (assuming a complete filename is in `$1`):

```
filebase=`basename "$1"`
lastpart=`echo -n ${filebase%.*} | tail -c3`

```

So for example, *"/path/to/somefile.txt"* ends up with *"ile"* in `$lastpart`.

Can I somehow combine `basename` and the bit to strip the suffix into a single command, and is there a way to send it to `tail` (or something else I can use) without using a pipe? The suffix is unknown so I can't base it as a parameter to `basename`.

The main goal isn't actually so much to be as short as possible, as to be as readable at a glance as possible. The actual context of all of this is [this question on Superuser](https://superuser.com/questions/772181/matching-files-to-folders/772190#772190), where I'm trying to come up with a reasonably simple answer.

Answer: 
```
var=123456
echo "${var#"${var%???}"}"

###OUTPUT###

456

```

That first removes the last three characters from `$var` then removes from `$var` the results of that removal - which returns the last three characters of `$var`. Here are some examples more specifically aimed at demonstrating how you might do such a thing:

```
touch file.txt
path=${PWD}/file.txt
echo "$path"

/tmp/file.txt

base=${path##*/}
exten=${base#"${base%???}"}
base=${base%."$exten"}
{ 
    echo "$base" 
    echo "$exten" 
    echo "${base}.${exten}" 
    echo "$path"
}

file
txt
file.txt
/tmp/file.txt

```

You don't have to spread this all out through so many commands. You can compact this:

```
{
    base=${path##*/} exten= 
    printf %s\\n "${base%.*}" "${exten:=${base#"${base%???}"}}" "$base" "$path"
    echo "$exten"
}

file 
txt 
file.txt 
/tmp/file.txt
txt

```

Combining `$IFS` with `set`ting shell parameters can also be a very effective means of parsing and drilling through shell variables:

```
(IFS=. ; set -f; set -- ${path##*/}; printf %s "${1#"${1%???}"}")

```

That will get you only the three characters immediately preceding the first period following the last `/` in `$path`. If you want to retrieve only the first three characters immediately preceding the last `.` in `$path` *(for instance, if there is a possibility of more than one `.` in filename)*:

```
(IFS=.; set -f; set -- ${path##*/}; ${3+shift $(($#-2))}; printf %s "${1#"${1%???}"}")

```

In both cases you can do:

```
newvar=$(IFS...)

```

And...

```
(IFS...;printf %s "$2")

```

...will print what follows the `.`

If you don't mind using an external program you can do:

```
printf %s "${path##*/}" | sed 's/.*\(...\)\..*/\1/'

```

If there is a chance of a `\n`ewline character in the filename *(not applicable for the native shell solutions - they all handle that anyway)*:

```
printf %s "${path##*/}" | sed 'H;$!d;g;s/.*\(...\)\..*/\1/'

```
If you can use `perl`:

```
lastpart=$(
    perl -e 'print substr((split(/\.[^.]*$/,shift))[0], -3, 3)
            ' -- "$(basename -- "$1")"
)

```