Find and xargs with BASH parameter expansion
Goal: to rename all the files with extensions to just their basenames without extensions. They have varied extensions. An extension is considered to be anything at the end up to and including the period/full-stop.
This is obviously much easier to do with a BASH "for name in $(ls somepatter); do .......", however the object of this exercise was to see how I can use parameter expansion to truncate the filenames returned by find. This mean using xargs, which in turn meant that I had to invoke a shell process. I am not proud of any of this :)...
findtests ls testfile1.txt testfile2.txt testfile3.txt testfile5.txt testfile6.otherext
This seems like a dead-end. Can output the modified names, however, where would we go from there?:
find -path "./*" -name "*\.*" -print0 | xargs --null -I name sh -c 'echo $( echo name | sed 's/txt/XXX/' )'
Find and use of parameter expansion with xargs for name change
Instead of using sed will used BASH parameter expansion here. The tricks were:
To invoke a sub-shell to delay processing of the BASH parameter expansions until after xargs has performed its substitutions into the argument list.
to assign the raw value of the filename passed in to a string so that it could be operated on with the usual parameter expansions. Simply trying to "rawname%%" did not work. Not sure if it might be possible to escape the curly-braces and percentages, but tried several variations on that and it failed.
To provide an explicit path to avoid the "." NULL otherwise returned by the -name regex used here
Also note the use of rawname instead of the common xargs argument list marker of "{}".
find -path "./*" -name "*\.*" -print0 | xargs --null -Irawname sh -c 'basename=rawname ; echo ${basename%.*}' ./testfile5 ./testfile6 ./testfile3 ./testfile1 ./testfile2
find -path "./*" -name "*\.*" -print0 | xargs --null -Irawname sh -c 'basename=rawname ; mv rawname ${basename%.*}'
ls testfile1 testfile2 testfile3 testfile5 testfile6
Doh... pipe straight out into sed and pipe that into xargs? https://en.wikipedia.org/wiki/Xargs
I later found this StackOverflow example which uses read in conjunction with a do...while. It avoids invoking a shell. A later modification of this answer by another user was:
#/bin/bash find -L . -type f -name '*.'$1 -print0 | while IFS= read -r -d '' file; do echo "renaming $file to $(basename ${file%.$1}.$2)"; mv -- "$file" "${file%.$1}.$2"; done
https://www.gnu.org/software/sed/manual/html_node/Regular-Expressions.html