Difference between ${v^^} and ${v@U}?

Viewed 76

Bash 4 had parameter expansion operations which allowed to convert string stored in variable to upper/lower case using ${v^}, ${v^^}, ${v,}, or ${v,,}. In Bash 5 new @ notation was added to provide various expansion operations, some of which also include case conversions: ${v^} == ${v@u}, ${v^^} == ${v@U}, ${v,,} == ${v@L} (no matching operator for ${v,} it seems).

What is the difference between ${v^^} and ${v@U}, and for what purpose new operators that do the same thing were added?

2 Answers

Expansions like ${x^^} take an optional pattern (that should match a single character at a time; it defaults to ? if omitted) that controls which characters are upper cased, while ${x@U} upper cases all characters. If you leave out the pattern in the first form they're equivalent, but if you specify one they're not the same. ${x^^[aeiou]} will only uppercase vowels, for example.

It seems that the code eventually end in the same function sh_modcase.

^^ and the family is expanded in parameter_brace_casemod, while the newer syntax is expanded in string_transform.

Looking at string_transform it's evident that other transformations are also possible:

  switch (xc)
    {
      /* Transformations that interrogate the variable */
      case 'a':
    i = var_attribute_string (v, 0, flags);
    ret = (i > 0) ? savestring (flags) : (char *)NULL;
    break;
      case 'A':
    ret = string_var_assignment (v, s);
    break;
      case 'K':
    ret = sh_quote_reusable (s, 0);
    break;
      /* Transformations that modify the variable's value */
      case 'E':
    t = ansiexpand (s, 0, strlen (s), (int *)0);
    ret = dequote_escapes (t);
    free (t);
    break;
      case 'P':
    ret = decode_prompt_string (s);
    break;
      case 'Q':
    ret = sh_quote_reusable (s, 0);
    break;
      case 'U':
    ret = sh_modcase (s, 0, CASE_UPPER);
    break;
      case 'u':
    ret = sh_modcase (s, 0, CASE_UPFIRST);  /* capitalize */
    break;
      case 'L':
    ret = sh_modcase (s, 0, CASE_LOWER);
    break;
      default:
    ret = (char *)NULL;
    break;
    }
Related