help-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Help-bash] Transform strings with special characters so that the st


From: Eric Blake
Subject: Re: [Help-bash] Transform strings with special characters so that the strings don't need to be quoted?
Date: Wed, 25 Mar 2015 15:42:35 -0600
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.5.0

On 03/25/2015 03:26 PM, Eric Blake wrote:

>>> printf -v escaped_var %q "$var"
> 
> Fork-free.

But requires bash extensions ('printf -v var' and 'printf %q' are both
bashisms not likely to work in other shells)


>>> shquote() {
>>>   local q=\'
>>>   printf "'%s'" "${1//"$q"/$q\\$q$q}"

And ${var//pattern/subst} is another bashism.

>>> }
>>> escaped_var=$(shquote "$var")
> 
> Requires a fork for the command substitution.
> 
>>
>> This is not robust with other characters that need to be escaped.
> 
> How so?  Single quote is the only character that needs to be
> special-cased when using single quoting.  What characters are you
> thinking of?
> 
> Or are you trying to escape a string to be suitable for use within ""
> instead of within '', as was done here?  If so, then you have a bit more
> work to do (\"$` are the four characters that need escaping), but it is
> still doable.  But why bother, when single quoting is easier?

For the record, here is one way of doing escaping for "" contexts
without forking, and limiting yourself to portable shell (no bashisms):

https://lists.gnu.org/archive/html/libtool/2015-03/msg00007.html

Original:
> sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
> _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"`

fork-free substitute:

# func_quote STRING
# Escapes all \`"$ in STRING with another \, and stores that in $quoted
func_quote () {
  case $1 in
    *[\\\`\"\$]*)
      save_IFS=$IFS pre=.$1.
      for char in '\' '`' '"' '$'; do
        post= IFS=$char
        for part in $pre; do
          post=${post:+$post\\$char}$part
        done
        pre=$post
      done
      IFS=$save_IFS post=${post%.}
      quoted=${post#.} ;;
    *) quoted=$1 ;;
  esac
}

func_quote "$1"
_G_unquoted_arg=$quoted

But that thread also had a nice followup observation:

> should we test the size of the string first ?  i've written such raw shell 
> string parsing functions before, and once you hit a certain size (like 1k+ 
> iirc), forking out to sed is way faster, especially when running in multibyte 
> locales (like UTF8) which most people are doing nowadays.


-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]