If, on the off-chance, you're just trying to handle quotes for reuse ion the shell, then you can do this without removing them, and it's dead simple, too:
aq() { sh -c 'for a do
alias "$((i=$i+1))=$a"
done; alias' -- "$@"
}
That function shell quotes any arg array you hand it and increments its output per iterable argument.
Here it is with a few args:
aq \
"here's an
ugly one" \
"this one is \$PATHpretty bad, too" \
'this one```****```; totally sucks'
OUTPUT
1='here'"'"'s an
ugly one'
2='this one is $PATHpretty bad, too'
3='this one```****```; totally sucks'
That output is from dash
which typically safe-quotes single-quoted output like '"'"'
. bash
would do '\''
.
Replacing a selection of single, non-whitespace, non-null bytes with another single byte can likely be done quickest in any POSIX shell with $IFS
and $*
.
set -f; IFS=\"\'\`; set -- $var; printf %s "$*"
OUTPUT
"some ""crazy """"""""string ""here
There I just printf
it so you can see it, but of course, if I had done:
var="$*"
...rather than the printf
command $var
's value would be what you see in the output there.
When I set -f
I instruct the shell not to glob - in case the string contains characters that could be construed as glob patterns. I do this because the shells parser expands glob patterns after it performs field splitting on variables. globbing can be re-enabled like set +f
. In general - in scripts - I find it useful to set my bang like:
#!/usr/bin/sh -f
And then to explicitly enable globbing with set +f
on whatever line I might want it.
Field splitting occurs based on the characters in $IFS
.
There are two kinds of $IFS
values - $IFS
whitespace and $IFS
non-whitespace. $IFS
whitespace (space, tab, newline) delimited fields are specified to elide by sequence to a single field (or none at all if they do not precede something else) - so...
IFS=\ ; var=' '; printf '<%s>' $var
<>
But all others are specified to evaluate to a single field per occurrence - they are not truncated.
IFS=/; var='/////'; printf '<%s>' $var
<><><><><>
All variable expansions are, by default, $IFS
delimited data arrays - they split out to separate fields according to $IFS
. When you "
-quote one you override that array property and evaluate it as a single string.
So when I do...
IFS=\"\'\`; set -- $var
I am setting the shell's argument array to the many $IFS
delimited fields generated by $var
's expansion. When it is expanded its constituent values for the characters contained in $IFS
are lost - they are only field separators now - they are \0NUL
.
"$*"
- like other double-quoted variable-expansions - also overrides the field-splitting qualities of $IFS
. But, in addition, it substitutes the first byte in $IFS
for each delimited field in "$@"
. So because "
was the first value in $IFS
all subsequent delimiters become "
in "$*"
. And the "
needn't be in $IFS
when you split it, either. You could alter $IFS
after set -- $args
to another value entirely and its new first byte would then show up for the field delimiters in "$*"
. What's more, you can remove all traces of them entirely like:
set -- $var; IFS=; printf %s "$*"
OUTPUT
some crazy string here
tr
. BASH's PE is good but tr is much faster in this case. e.g.echo "$OUTPUT" | tr -dc '[[:alpha:]]'
since you want to have alphanumerics only – Valentin Bajrami Oct 15 '14 at 10:12echo "$OUTPUT"
. Or better:printf "%s\n" "$OUTPUT"
. (What happens whenOUTPUT="-n"
?) – musiphil Oct 15 '14 at 17:12