3

I regularly use the expression line=${line//[$'\r\n']}. But what does [$'\r\n'] mean?

I know it removes the '\r\n' characters but how does it do this? Does it remove the instances of both characters only, or does it also find matches of just one character?

I do not understand the usage of this syntax.

If you can, please, give me a link to the manual. I cannot find the answer on this question.

xUr
  • 245

3 Answers3

8

This command removes all carriage return and line feed bytes from the line variable.

This is a Bash (and zsh, and ksh) extension to parameter expansion: ${line//XYZ} replaces all matches of the pattern XYZ in $line with nothing.

The pattern [$'\r\n'] has two components: [...] matches any of the characters inside it. $'\r\n' is ANSI-C quoting (another extension), and expands to the carriage return (\r) and line feed (\n) bytes, so [$'\r\n'] is [...] with a carriage return and line feed inside it, and so matches both of them.

The full manual of shell commands, operators, brackets, etc is here, part of the POSIX/SUS/IEEE 1003.1 specification. The Bash reference manual is here.

Michael Homer
  • 76,565
  • Note that this is an instance of regular expression https://en.wikipedia.org/wiki/Regular_expression syntax, which can be found in many *nix utilities (and elsewhere), from command-line utilities like awk & sed to text editors to programming libraries like (f)lex. – jamesqf Jul 13 '19 at 16:57
  • 4
    @jamesqf, no, it isn't. The pattern in the ${var/pattern/substitution} is a same kind of a pattern used for globbing filenames, not a regular expression. It's just that [abc] works the same in both, but try e.g. var=abcd; echo ":${var//.*}:${var//*}:". See e.g. this answer (which also includes glob patterns, and not just regexes mentioned in the question title) – ilkkachu Jul 13 '19 at 17:06
5

From the Bash manual:

${parameter/pattern/string}
The pattern is expanded to produce a pattern just as in filename expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. The match is performed according to the rules described below (see Pattern Matching). If pattern begins with /, all matches of pattern are replaced with string. ... If string is null, matches of pattern are deleted and the / following pattern may be omitted.

You have ${line//[$'\r\n']}, where:

  • the parameter is line,
  • the pattern is /[$'\r\n'] (note: begins with /, so all matches of pattern are replaced), and
  • the string is null, so the / after pattern is omitted, and matches are deleted.

Following the rules for Pattern Matching:

[…]
Matches any one of the enclosed characters.

$'...' tells bash to interpret certain escape sequences (here, \r for carriage return and \n for line feed) and replace them with actual characters represented by the escape sequences.

So this substitution matches all instances of either carriage return (CR, \r) or line feed (LF, \n), and deletes them.

muru
  • 72,889
-2

The $ means: look at the end of line for the pattern The pattern is '\r\n'; meaning: \r (carage return) \n (new line)

The Square brackets [ ] are used to enclose what is being searched for on the individual line