Skip to main content
deleted 1 character in body
Source Link
Michael Homer
  • 78.9k
  • 17
  • 221
  • 239

That is, it genuinely runs the user's login shell, and then passes whatever command you gave sudo to theit using -c - unlike what sudo cmd arg arg usually does without the -i option. Ordinarily, sudo just uses one of the exec* functions directly to start the process itself, with no intermediate shell and all arguments passed through exactly as-is.

That is, it genuinely runs the user's login shell, and then passes whatever command you gave sudo to the using -c - unlike what sudo cmd arg arg usually does without the -i option. Ordinarily, sudo just uses one of the exec* functions directly to start the process itself, with no intermediate shell and all arguments passed through exactly as-is.

That is, it genuinely runs the user's login shell, and then passes whatever command you gave sudo to it using -c - unlike what sudo cmd arg arg usually does without the -i option. Ordinarily, sudo just uses one of the exec* functions directly to start the process itself, with no intermediate shell and all arguments passed through exactly as-is.

added 1056 characters in body
Source Link
Michael Homer
  • 78.9k
  • 17
  • 221
  • 239

Let's start with your simplified command:

sudo bash -c 'echo 1
echo 2'

In this case, sudo changes user, then runs execvp("bash", \["bash", "-c", "echo 1\necho 2"\]) (for an invented array literal syntax).

With -i:

sudo -i bash -c 'echo 1
echo 2'

instead it changes user, then runs execv("/bin/bash", ["-bash", "-c", "bash -c echo\\ 1\\\necho\\ 2"]), where \\ equates to a literal \ and \n is a linebreak. It's escaped the spaces and the newline in your main command by preceding them with backslashes.

That is, there's an outer login shell, which has two arguments: -c and your entire command, reconstructed into a form the shell is expected to understand correctly. Unfortunately, it doesn't. The inner bash command ultimately tries to run:

echo 1\
echo 2

where the first physical line ends with a line continuation (backslash followed by newline), which is deleted entirely. The logical line is then just echo 1echo 2, which doesn't do what you wanted.

There's an argument that this is a flaw in sudo's escaping, given the standard behaviour of backslash-newline pairs. I think it should be safe to leave them unescaped here.


The same happens for your command with a here-document. It runs as, roughly:

So that's your problem: the inner bash process gets only one line of command, and so the here-document never gets a chance to end (or start). I have some imperfect solutions at the bottom, but this is the underlying cause.

There's an argument that this is a flaw in sudo's escaping, given the standard behaviour of backslash-newline pairs. I think it should be safe to leave them unescaped here.

The same happens for your command. It runs as, roughly:

So that's your problem: the inner bash process gets only one line of command, and so the here-document never gets a chance to end (or start). I have some imperfect solutions at the bottom, but this is the underlying cause.

There's an argument that this is a flaw in sudo's escaping, given the standard behaviour of backslash-newline pairs. I think it should be safe to leave them unescaped here.

Let's start with your simplified command:

sudo bash -c 'echo 1
echo 2'

In this case, sudo changes user, then runs execvp("bash", \["bash", "-c", "echo 1\necho 2"\]) (for an invented array literal syntax).

With -i:

sudo -i bash -c 'echo 1
echo 2'

instead it changes user, then runs execv("/bin/bash", ["-bash", "-c", "bash -c echo\\ 1\\\necho\\ 2"]), where \\ equates to a literal \ and \n is a linebreak. It's escaped the spaces and the newline in your main command by preceding them with backslashes.

That is, there's an outer login shell, which has two arguments: -c and your entire command, reconstructed into a form the shell is expected to understand correctly. Unfortunately, it doesn't. The inner bash command ultimately tries to run:

echo 1\
echo 2

where the first physical line ends with a line continuation (backslash followed by newline), which is deleted entirely. The logical line is then just echo 1echo 2, which doesn't do what you wanted.

There's an argument that this is a flaw in sudo's escaping, given the standard behaviour of backslash-newline pairs. I think it should be safe to leave them unescaped here.


The same happens for your command with a here-document. It runs as, roughly:

So that's your problem: the inner bash process gets only one line of command, and so the here-document never gets a chance to end (or start). I have some imperfect solutions at the bottom, but this is the underlying cause.

added 76 characters in body
Source Link
Michael Homer
  • 78.9k
  • 17
  • 221
  • 239

where \012 represents an actual newline - sudo has inserted a backslash before each of them, just like the spaces. Note the double-escaping on \\012: that's ps's rendition of an actual backslash followed by newline, which I'm using here (see below). What eventually runs is:

where \012 represents an actual newline. Note the double-escaping on \\012: that's ps's rendition of an actual backslash followed by newline, which I'm using here (see below). What eventually runs is:

where \012 represents an actual newline - sudo has inserted a backslash before each of them, just like the spaces. Note the double-escaping on \\012: that's ps's rendition of an actual backslash followed by newline, which I'm using here (see below). What eventually runs is:

added 885 characters in body
Source Link
Michael Homer
  • 78.9k
  • 17
  • 221
  • 239
Loading
Source Link
Michael Homer
  • 78.9k
  • 17
  • 221
  • 239
Loading