Home > Software engineering >  sed: Can't replace latest text occurrence including "-" dashes using variables
sed: Can't replace latest text occurrence including "-" dashes using variables

Time:12-18

Trying to replace a text to another with sed, using a variable. It works great until the variable's content includes a dash "-" and sed tries to interpret it.

It is to be noted that in this context, I need to replace only the latest occurrence of the origin variable ${src}, which is why my sed command looks like this:

sed -e "s:${source}([^${source}]*)$:${dest}\1:"

"sed" is kind of new to me, I always got my results with "replace" or "awk" whenever possible, but here I'm trying to make the code as versatile as possible, hence using sed. If you think of another solution, that is viable as well.

Example for the issue:

# mkdir "/home/youruser/TEST-master"
# source="TEST-master" ; dest="test-master" ; find /home/youruser/ -depth -type d -name '*[[:upper:]]*' | grep "TEST" | sed -e "s:${source}([^${source}]*)$:${dest}\1:"
sed: -e expression #1, char 46: Invalid range end

Given that I don't know how many dashes every single variable may contain, does any sed expert know how could I make this work?

Exact context: Open source project LinuxGSM for which I'm rewriting a function to recursively lowercase files and directories. Bash function I'm working on and comment here: https://github.com/GameServerManagers/LinuxGSM/issues/1868#issuecomment-996287057

CodePudding user response:

If I'm understanding the context right, the actual goal is to take a path that contains some uppercase characters in its last element, and create a version with the last element lowercased. For example, /SoMe/PaTh/FiLeNaMe would be converted to /SoMe/PaTh/filename. If that's the case, rather than using string substitution, use dirname and basename to split it into components, uppercase the last, then reassemble it:

parentdir=$(dirname "$src")
filename=$(basename "$src")
lowername=$(echo "${latestpath}" | tr '[:upper:]' '[:lower:]')
dst="$parentdir/$lowername"

(Side note: it's important to quote the parameters to tr, to make sure the shell doesn't treat them as filename wildcards and replace them with lists of matching files.)

As long as the paths contain at least one "/" but not end with "/", you can use bash substitutions instead of dirname and basename:

parentdir="${src%/*}"
filename="${src##*/}"

As long as you're using bash v4.0 or later, you can also use a builtin substitution to do the lowercasing:

lowername="${filename,,}"
  • Related