Search code examples
bashmodifierchain

How can I chain together filename modifiers in a bash shell?


I understand the modifiers # ## % %%, but I can't figure out if its possible to chain them together as you can in tcsh.

Example in tcsh

set f = /foo/bar/myfile.0076.jpg
echo $f:r:e
--> 0076

echo $f:h:t
--> bar

In bash, I'd like to know how to do something like:

echo ${f%.*#*.}

in one line.

My goal is to be able to manipulate filenames in various ways as and when needed on the command line. I'm not trying to write a script for one specific case. So if there is a way to chain these modifiers, or maybe there's another way, then I'd love to know. Thanks


Solution

  • I found a solution that gets pretty close to the simplicity of the tcsh filename modifiers. I wrote 4 functions and put them in .bashrc.

    e() # the extension
    E() # everything but the extension
    t() # the tail - i.e. everything after the last /
    T() # everything but the tail (head)
    

    Definitions are at the end.

    These functions can accept an argument like so:

    f=foo/bar/my_image_file.0076.jpg
    e $f
    --> jpg
    E $f
    --> foo/bar/my_image_file.0076
    

    or accept input from a pipe, which is the feature from tcsh that I really wanted:

    echo $f|E|e
    --> 0076
    

    or of course, a combination:

    T $f|t
    --> bar
    

    and it just dawned on me it will accept many files through the pipe:

    ls foo/bar/
    --> my_image_file.0075.jpg  my_image_file.0076.jpg
    ls foo/bar/ |E|e
    --> 0075
    --> 0076
    

    Definitions:

    #If there are no args, then assume input comes from a pipe.
    
    function e(){
        if [ $# -ne 0 ]; then
            echo ${1##*.}  
        else
            while read data; do
                echo  ${data##*.}   ; 
            done
        fi
    }
    
    function E(){
        if [ $# -ne 0 ]; then
            echo ${1%.*} 
        else
            while read data; do
                echo ${data%.*}
            done
        fi
    }
    
    function t(){
        if [ $# -ne 0 ]; then
            echo ${1##*/}  
        else
            while read data; do
                echo  ${data##*/}   ; 
            done
        fi
    }
    
    function T(){
        if [ $# -ne 0 ]; then
            echo ${1%/*} 
        else
            while read data; do
                echo ${data%/*}
            done
        fi
    }