BASH Expression to replace the beginning and end of a string in one operation?

Here is a simple problem that has been pushing me for some time. I often find that I have multiple input files in some directory and I want to construct the names of the output files by replacing the beginning and ending parts. For example, given this:

source/foo.c
source/bar.c
source/foo_bar.c

      

I often end up writing BASH expressions like:

for f in source/*.c; do
  a="obj/${f##*/}"
  b="${a%.*}.obj"
  process "$f" "$b"
done

      

to generate commands

process "source/foo.c"    "obj/foo.obj"
process "source/bar.c     "obj/bar.obj"
process "source/foo_bar.c "obj/foo_bar.obj"

      

The above works, but it is much longer than I like and I would rather avoid temporary variables. Ideally, there would be some command that could replace the beginning and end of a line with a single shot, so I could just write something like:

for f in source/*.c; do process "$f" "obj/${f##*/%.*}.obj"; done

      

Of course the above doesn't work. Does anyone know what will happen? I'm just trying to save myself from typing.

+2


a source to share


4 answers


Not the prettiest thing in the world, but you can use a regex to group the content you want to highlight and then access the array BASH_REMATCH

:



if [[ $f =~ ^source/(.*).c$ ]] ; then f="obj/${BASH_REMATCH[1]}.o"; fi

      

+3


a source


you don't need to worry about whether your code is "wordier" or not. Actually, being a little verbose, it doesn't hurt, consider how much it will improve your (or other) understanding of the script. Also, for performance, bash's use of internal string processing is much faster than calling external commands. And finally, are you not going to re-specify your commands every time you use it correctly? So why bother with its "wordier" since those commands are already in your script?



+1


a source


Not directly in bash. You can use sed of course:

b="$(sed 's|^source/(.*).c$|obj/$1.obj|' <<< "$f")"

      

0


a source


Why not just use cd to remove the "source /" part?

This way we can avoid temporary variables a and b:

for f in $(cd source; printf "%s\n" *.c); do
   echo process "source/${f}" "obj/${f%.*}.obj"
done

      

0


a source







All Articles