I want to find all files that match a pattern and append a string to the prefix, preserving the extension if it exists. Some of the files have extensions and others don't.
Desired transform:
tools-win/foo.exe => tools-win/foo_bar.exe
tools-osx/foo => tools-osx/foo_bar
Is there a way to do this with bash parameter expressions? My current attempt is:
find . -path 'tools-*/*' \
-execdir sh -c 'mv "$1" "${1%.*}_$2.${1##.}"' _ {} bar \;`
This works on files that have extensions, but captures the entire prefix for files that have no extensions:
tools-win/foo.exe => tools-win/foo_bar.exe
tools-osx/foo => tools-osx/foo_bar.foo
Is there a single parameter expression I can use here that handles both cases?
The inner shell script can parse out the prefix by stripping everything including and after the final .
, and then the suffix by stripping the prefix out of the original string. The final string can be assembled with standard concatenation:
PREFIX=${1%.*}
SUFFIX=${1##"${PREFIX}"}
FINAL=${PREFIX}_bar${SUFFIX}
Note that if ${PREFIX}
is identical to the input string, ${SUFFIX}
will be empty.
So while it's not a one-liner inside sh
, an invocation that only calls find -exec
once without pipes looks like this:
find "${PATH_TO_SEARCH}" -path "${PATH_TO_SEARCH}/tools-*/*" \
-execdir sh -c 'p=${1%.*};s=${1##"${p}"};mv "$1" "${p}_$2${s}"' sh {} bar \;`