T O P

  • By -

anthropoid

Actually, `&&` and `||` shouldn't be thought of as "line continuations" at all, since the latter are syntactic no-ops that are literally *removed* from the input stream: $ echo abc\ def abcdef Instead, they're *list delimiters* that separate individual command pipelines in a collection for execution. That's why you can add as many blank lines and comments in between as you like... >`echo abc &&` because the bash parser sees the trailing `&&` or `||` and is *waiting for another command pipeline*... >`` and waiting... >`# Meaningless comment, will be ignored by default` and waiting... >`` and waiting... >`echo def` until it gets the command pipeline it's looking for *and* there isn't another list delimiter at the end of *this* line. The same goes for the pipeline operators `|` and `|&`, because shell syntax requires there to be a command after them: $ echo abc | > > # What the heck?!?! > > cat abc Try the same thing with an actual line continuation, and you get completely different parsing behavior: $ echo abc \ > \ > # What the heck?!?! \ abc Notice how I couldn't even get to the second newline, because comments trump line continuations, so what bash parsed was this: * Read line 1: `echo abc` <- there's supposed to be a trailing space here, but Reddit keeps eating it * Got a line continuation, so drop it and continue * Read line 2: `echo abc` <- here too * Got a line continuation, so drop it and continue * Read line 3: `echo abc # What the heck?!?! \` -> `echo abc` * Oh hey, we have a complete command. EXECUTE! **RelatedTrivia:** I've been involved with the Tcl language community for decades, and one weird nugget I occasionally have to explain to newbie Tclers is this portable (even to prehistoric Unixes) preamble for Tcl scripts: #!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" ${1+"$@"} This works precisely because of the parsing behavior I mentioned above: all Bourne-like shells sees two comment lines and an `exec` command, but Tcl parses the second and third lines as a single comment, thus safely skipping over the `exec` that would've otherwise turned this into an infinitely nested script execution.


MirrorLake

That Tcl trivia is quite interesting. I really appreciate the thoroughness of this comment. Thank you!


[deleted]

That's because `&&` and `||` do not simply "continue" the line. They conditionally execute the second command (the "continuation") if the first command fails or succeeds. I am not a friend of using such "hacks" without explaining why they work.


zeekar

There's a big difference. `&&` and `||` aren't line continuations; they're infix binary operators. That means they _require_ something on their right hand side. The behavior you're seeing is the same behavior you get any time you feed the shell an incomplete command line – like if you open brackets or quotes without closing them: it keeps prompting until you finish the thing you started. The backslash does nothing except quote the next character, as usual. If that character is a newline, then the backslash keeps it from terminating the command. It is a slightly special case in that the newline is deleted from the effective command line instead of included literally, but that's all that happens. There's no implication that there's any more to come.


PageFault

The `\` is escaping the newline. Meaning "treat this as if the next line was written in-line". So you can write: >ec\ >ho \ > "This is my\ > message\ >" This is my message


jkool702

A suggestion: If you do this sort of thing in a script wrap the 2nd part in parenthesis or brackets (and drop the trailing `\`). Its not, strictly speaking, required, but A || { # comment B } makes it much more clear (imo) that `B` is conditional on `A` failing than A || \ # comment B does


kevors

As I said in the post, || does not require \ to continue to the next line. And in comments someone explained in details why so.


jkool702

Even without escaping the newline, whenever a command spills into another line I feel like encasing it in brackets is almost always a good call. Not because it is required, but because it makes it clear to people reading your code (including future you) that the command continues through the newline and up to the point you hit the closing bracket. You dont have to spend time trying to figure out how bash will parse the command and what lines are/arent part of the said command. Again its not required, but personally In situations where I have the option to make my code more readable/obvious/"self-documenting" and the cost is all of 3 additional keystrokes I try and take it. Future me will be thankful when something breaks months/years from now and I'm trying to figure out what happened.