0

I have this:

second_arg="${second_arg/[^[:alnum:]]/_}"

if I do this:

second_arg="foo::"
second_arg="${second_arg/[^[:alnum:]]/_}"
echo "$second_arg"

then I get:

foo_:

how do I replace all instances of non-alphanumerics? I tried a global switch like this:

 second_arg="${second_arg/[^[:alnum:]]/_/g}"

but that didn't work, I ended up getting:

foo_:/g
5

Or, if you want to stick with bash's variable expansion features, use two forward-slashes to replace every match with the replacement:

second_arg="${second_arg//[^[:alnum:]]/_}"
                         ^------ here
  • thanks do you happen to know what this is called? – Alexander Mills Oct 5 '18 at 17:54
  • 1
    Parameter expansion under "${parameter/pattern/string}", where you probably already were, but hidden in this: "If pattern begins with ‘/’, all matches of pattern are replaced with string." – Jeff Schaller Oct 5 '18 at 17:56
  • 1
    The idea is that the "first" and "last" forward slashes are syntactically required, so the "second" slash is a "pattern that begins with /". – Jeff Schaller Oct 5 '18 at 17:56
  • No, a pattern that start with slash is \/pattern. The second / has a syntactic meaning: repeated (like g in sed s///g). – Isaac Oct 6 '18 at 0:38
2

Expanding on Jeff Schaller's answer, there are various things that "search and replace" parameter substition can do:

Given: s="_one_two_one_two"

  1. replace the first "two"

    $ echo ${s/two/X}
    _one_X_one_two
    
  2. replace all "two"

    $ echo ${s//two/X}
    _one_X_one_X
    
  3. replace "two" if it is anchored at the end of the string

    $ echo ${s/%two/X}
    _one_two_one_X
    
  4. replace "one" if it is anchored at the start of the string (it is not, no replacement)

    $ echo ${s/#one/X}
    _one_two_one_two
    
1

With sed:

$ echo 'This is a test; specifically it is test number 25!' | sed 's/[^a-zA-Z0-9]/_/g'
This_is_a_test__specifically_it_is_test_number_25_
  • for some reason I saw people using sed -r instead of sed not sure what the difference is, but the -r option is not available on MacOS. – Alexander Mills Oct 5 '18 at 17:36
  • 1
    sed -r is functionally the same as sed -E. -E is not needed for this usage, however -- the above example was tested on a Mac, as it happens. – DopeGhoti Oct 5 '18 at 17:39
  • I have to support both MacOS and Linux so I need something x-platform. Is there a x-platform tag/label for questions on unix.stackexchange? Right now this seems to work: second_arg="${second_arg//[^[:alnum:]]/_}" – Alexander Mills Oct 5 '18 at 17:42
  • note the double forward slash instead of the single forward slash – Alexander Mills Oct 5 '18 at 17:43
1

In bash (as you are using) a ${arg/one/two} will replace only the first occurrence of on. To replace all double the first / as this ${arg/one/two}, so, for your case:

arg=${arg//[^[:alnum:]]/_}

The second slash could be changed to # to mean start and to % to mean end.

If the string is:

➤ a=one_two_/one_two_one

To change the first instance (only) of one:

➤ echo ${a/one/xXx}
xXx_two_/one_two_one

The first instance of two:

➤ echo ${a/two/xXx}
one_xXx_/one_two_one

The string one at the start of the parameter:

➤ echo ${a/#one/xXx}
xXx_two_/one_two_one

The string one at the end of the parameter:

➤ echo ${a/%one/xXx}
one_two_/one_two_xXx

The string /one (start with a slash):

➤ echo ${a/\/one/xXx}
one_two_xXx_two_one

All the repetitions of one:

➤ echo ${a//one/xXx}
xXx_two_xXx_two_xXx

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.