text:
Sing Baby Shark

"Baby Shark" is a children's song about a family of sharks. Having long been popular as a campfire song, it has been popularized since the mid-2000s by social media, online video and radio. - Wikipedia

Write program that takes no input, and writes the following text to the standard output or an arbitrary file:
Baby Shark doo doo doo doo doo doo
Baby Shark doo doo doo doo doo doo
Baby Shark doo doo doo doo doo doo
Baby Shark!
Daddy Shark doo doo doo doo doo doo
Daddy Shark doo doo doo doo doo doo
Daddy Shark doo doo doo doo doo doo
Daddy Shark!
Mommy Shark doo doo doo doo doo doo
Mommy Shark doo doo doo doo doo doo
Mommy Shark doo doo doo doo doo doo
Mommy Shark!
Grandpa Shark doo doo doo doo doo doo
Grandpa Shark doo doo doo doo doo doo
Grandpa Shark doo doo doo doo doo doo
Grandpa Shark!
Grandma Shark doo doo doo doo doo doo
Grandma Shark doo doo doo doo doo doo
Grandma Shark doo doo doo doo doo doo
Grandma Shark!

This is code golf — shortest code wins.
Found this on Reddit^1^2, and it seems like an interesting challenge to golf.
Updates:
No newline between stanzas, that makes it too easy :)
Leading/trailing newlines are okay.

Is a newline between each stanza (each shark) acceptable? (That's always how I've seen the lyrics written)

(See above comment, since you've responded to my other ones but seem to have skipped this one)

Updated original post. I know you could save a few bytes by doing \n before every stanza (that way you don't have to avoid making a newline at the end), but people already started doing it this way so I think keeping it as is is fair.

Eh, missing a few verses, like all the ones about the swimmers swimming and losing limbs in shark attacks.

Are leading or trailing newlines or spaces permitted? Can we return an array of lines?

Leading/trailing newlines are okay, arrays wouldn't be (unless they printed to stdout/a file in the correct format.

Why is the mommy/daddy and grandma/grandpa order switched in your post? I'd be susprised if any of the answers change byte counts if you corrected it.

"doo doo doo doo doo doo" is really over-simplified.

As a parent, I feel the strongest urge to downvote this one.  I'm repressing the urge because that's not how Stack Exchange works.  But if I find myself humming "doo doo doo doo" later today, I'm coming back here and holding you accountable!

How many people's days ruined now that this is on HNQs?

@CactusCake, our days are often ruined here by some of the challenges that make into HNQ! :D

I find myself restraining myself to say "doo doo doo doo" after reading this challenge.

@CortAmmon I personally found the song so bad I couldn't listen to it long enough for it to become an earworm.  I see "doo doo doo" and think "come on and do the conga" instead. Well, that or "push pineapple, shake a tree"

How does the Wikipedia article for this not have any lyrics or describe the hand motions?  I guess adults are just that tired of this song...

The new FizzBuzz? :)

@CortAmmon been there, done that, got the t-shirt (Christmas present from my daughter).  In fact now I'm humming in danger of humming it to a metal backing track!

Amazing! I can't believe this is the first time this was thought of.

@nija I don't think removing the newline makes it any harder...

SOGL, 40 bytes
o⅝ηvΒvPΝ┘÷ΖnΨ‘θ{"nOe;‘+ū:" doo”6*+TTPPļ!

Try it here!

Emojicode, 292 bytes (140 characters)
Baby➡bDaddy➡yMommy➡oGrandpa➡gGrandma➡a Shark➡s doo➡db y o g a➡fm fi⏩⏩0 3❗m s d d d d d d❗m s!❗

Run it
Expanded out:

  Baby ➡ b
  Daddy ➡ y
  Mommy ➡ o
  Grandpa ➡ g
  Grandma ➡ a
   Shark ➡ s
   doo ➡ d
  b y o g a➡f
  m f
    i⏩⏩0 3❗
      m s d d d d d d❗

    m s!❗

Explained (per the Emojicode doc):

The same as a { and } (e.g. a code block)

The "program start" (e.g. int main())
Baby ➡ b

Variable assignment (e.g. const char* b = "Baby";)
b y o g a➡f

Says, create a list of values between  and  and assign (➡) to f (e.g. const char* f[] = {b,y,o,g,a};)
m f ...

This line says to loop over the elements in f using the alias m, where the ... is the code between  and .
 i ⏩⏩ 0 3❗ ...

This line says to loop over the range [0,3), where the ... is the code between  and .
 ... ❗

This line says to print the format specified in ... (e.g. printf("%s\n");)
The code translated to C:
#include <stdio.h>

int main() {
  const char* b = "Baby";
  const char* y = "Daddy";
  const char* o = "Mommy";
  const char* g = "Grandpa";
  const char* a = "Grandma";
  const char* s = " Shark";
  const char* d = " doo";
  const char* f[] = {b,y,o,g,a};
  int m = 0, i = 0;
  for (; m < 5; ++m) {
    for (i = 0; i < 3; ++i) {
      printf("%s%s%s%s%s%s%s%s\n", f[m], s, d, d, d, d, d, d);
    }
    printf("%s%s!\n", f[m], s);
  }
  return 0;
}

Following this, the original code (posted below for posterity) had some issues; mostly that the  block was not included for those who wish to run it, and the emoji's were not actually properly escaped, to that, here is the actual running version of that code:
Original modified to run: Emojicode, 224 bytes (67 characters)
➡fm fi⏩⏩0 3❗m❗m!❗

Expanded out:

   ➡ f
   m f
     i ⏩⏩ 0 3❗
      m❗

    m!❗

Which produces the output:

!

!

!

!

!

Run it
Where in you have the individual emoji's representing the words:
 -> Baby
 -> Daddy
 -> Mommy
 -> Grandpa
 -> Grandma
 -> Shark
 -> doo

Original: Emojicode, 138 bytes (47 characters)
➡fm fi⏩⏩0 3❗m❗m!❗

Expanded out:
➡f
m f
   i ⏩⏩ 0 3❗
     m ❗

   m !❗

Points for creativity, but this doesn't produce the required output

Welcome to the site! As JoKing was getting at we require that answers do exactly what the question ask here.  This means that while your interpretation of the challenge is creative this answer should either be fixed to produce the correct output or deleted.

While this answer is creative, it does not follow the requirements of the challenge, and thus is not valid - the text must be output exactly as stated in the challenge.

Please either modify this answer to produce the correct output, or delete it.

You need half the poop emojis, since  is "doo doo" :) While I agree it's not a valid entry, you definitely deserve points for creativity.

Welcome to the site! When I try to run this code online, I get an error. (It also counts 98 characters instead of 94). Am I missing something?

+1 now you've also included the textual output. :) But I indeed noticed the same thing as @DJMcMayhem in both Emojicode and Emojicode 0.5 on TIO. Is TIO a different version and it therefore errors? Or is your submission a function instead of full program and do we need anything more in the header/footer? I don't know Emojicode, but I'm curious why it doesn't work on TIO.

@DJMcMayhem .. I honestly didn't think this would get such recognition, so I learned Emojicode in about 5 minutes and threw together this answer in about 15 minutes for fun :) That being said, I've since had a few more minutes to learn the language more and have modified the answer to run properly. That'll teach me to joke around!❗

This answer has earned more reputation than I have. Emojicode for the win!

x86-16 machine code, IBM PC DOS, 108 107 bytes
00000000: bd42 01e8 1600 bd47 01e8 1000 bd4d 01e8  .B.....G.....M..
00000010: 0a00 bd53 01e8 0400 c646 056d b409 b104  ...S.....F.m....
00000020: 8bd5 cd21 ba5b 01cd 21e2 06ba 6701 cd21  ...!.[..!...g..!
00000030: c3b3 06ba 6201 cd21 4b75 fbba 6801 cd21  ....b..!Ku..h..!
00000040: ebde 4261 6279 2444 6164 6479 244d 6f6d  ..Baby$Daddy$Mom
00000050: 6d79 2447 7261 6e64 7061 2420 5368 6172  my$Grandpa$ Shar
00000060: 6b24 2064 6f6f 2421 0d0a 24              k$ doo$!..$

Unassembled:
BD 0142         MOV  BP, OFFSET BABY        ; Baby Shark
E8 011C         CALL VERSE
BD 0147         MOV  BP, OFFSET DADDY       ; Daddy Shark
E8 011C         CALL VERSE
BD 014D         MOV  BP, OFFSET MOMMY       ; Mommy Shark
E8 011C         CALL VERSE
BD 0153         MOV  BP, OFFSET GRAND       ; Grandpa/ma Shark
E8 011C         CALL VERSE
C6 46 05 6D     MOV  BYTE PTR [BP][5], 'm'  ; change 'p' to 'm'
            VERSE:
B4 09           MOV  AH, 9                  ; DOS API display string function
B1 04           MOV  CL, 4                  ; loop verse counter
            LOOP_VERSE:
8B D5           MOV  DX, BP                 ; load shark name from BP
CD 21           INT  21H                    ; display shark name
BA 015B         MOV  DX, OFFSET SHARK       ; load 'Shark'
CD 21           INT  21H                    ; display 'Shark'
E2 06           LOOP LOOP_DOO               ; if not last line, write 'doo's
BA 0167         MOV  DX, OFFSET BANG        ; otherwise end with a bang
CD 21           INT  21H                    ; display !, CRLF
C3              RET                         ; return from CALL or to DOS
            LOOP_DOO:
B3 06           MOV  BL, 6                  ; loop 'doo' 6 times
BA 0162         MOV  DX, OFFSET DOO         ; load 'doo' string
            PRINT_DOO:
CD 21           INT  21H                    ; display 'doo'
4B              DEC  BX                     ; decrement doo count
75 FB           JNZ  PRINT_DOO              ; if not last doo, start again
BA 0168         MOV  DX, OFFSET CRLF        ; load CRLF string
CD 21           INT  21H                    ; display CRLF
EB DE           JMP  LOOP_VERSE             ; repeat verse

BABY    DB  'Baby$'
DADDY   DB  'Daddy$'
MOMMY   DB  'Mommy$'
GRAND   DB  'Grand'
PA      DB  'pa$'
SHARK   DB  ' Shark$'
DOO     DB  ' doo$'
BANG    DB  '!'
CRLF    DB  0DH,0AH,'$'

Try it online!
Output

(TODO: update this screenshot for one less byte...)

You absolute madman.

When you said Download SHARK.COM!, I immediately thought of computer viruses.

@gwaugh I was kidding

@gwaugh But it's 109 bytes

Python 2, 93 bytes
for w in"Baby Daddy Mommy Grandpa Grandma".split():w+=" Shark";print(w+" doo"*6+"\n")*3+w+"!"

Try it online!
94 bytes
for w in"Baby Daddy Mommy Grandpa Grandma".split():print((" doo"*6+"\n%s Shark"%w)*4)[25:]+"!"

Try it online!

05AB1E, 50 41 bytes
“‡ÍÊÐ¢×myîºpaîºma“#ð«'ã¢«™v…doo6иyšÐy'!«»

Last part v4FN3Qiy'!«ë…doo6иyšðý}, can definitely be golfed a bit.. And I was right, -9 bytes thanks to @Emigna (even more than I was expecting).
Try it online.
Explanation:
“‡ÍÊÐ¢×myîºpaîºma“ # Push dictionary string "baby daddy mommy grandpa grandma"
 #                 # Split by spaces: ["baby","daddy","mommy","grandpa","grandma"]
  ð«               # Append a space to each
    'ã¢«          '# Append dictionary string "shark" to each
        ™          # Title-case each word
v                  # Loop `y` over these strings
 …doo              #  Push string "doo"
     6и            #  Repeat it 6 times as list
       yš          #  Prepend the string `y` at the front of the list
         Ð         #  Triplicate this list
 y'!«             '#  Push string `y`, concatted with a "!"
 »                 #  Join everything on the stack by newlines
                   #  (and each list implicitly by spaces)
                   # (and after the loop, output the result implicitly)

See this 05AB1E tip of mine (section How to use the dictionary?) to understand why “‡ÍÊÐ¢×myîºpaîºma“ is "baby daddy mommy grandpa grandma" and 'ã¢ is "shark".

You can golf 9 bytes of that last bit with v…doo6иyšÐy'!«»

@Emigna You even golfed more than I was expected, thanks! Smart way of using the triplicate and »!

PowerShell, 88 86 85 80 79 76 bytes
-5 bytes thanks to @mazzy
-1 byte thanks to @Joey
-3 bytes thanks to @AdmBorkBork
echo Baby Daddy Mommy Grandpa Grandma|%{,(($a="$_ Shark")+" doo"*6)*3;"$a!"}

Try it online!
We've certainly come a long way.
PowerShell (with Text to Speech), 156 bytes
This is NOT up to spec, but it's kinda funny. Thanks to @rkeet for the idea!
Add-Type -a System.Speech;echo Baby Daddy Mommy Grandpa Grandma|%{(New-Object Speech.Synthesis.SpeechSynthesizer).Speak((($a="$_ Shark")+" doo"*6)*3+" $a")}

.NET Text to speech pronunciation is... well... interesting. Keep this in mind when listening. Enjoy!

80 bytes :)

You can save another byte by assigning "$_ Shark" to a variable and re-using it.

76 bytes using echo instead of -split.

I think you should have a "text to speech" in there as well :p For the hell of it tried to combine it a bit with this code, didn't quite work :-)

@rkeet Challenge accepted! I am currently puzzling this out.

Java (JDK), 135 bytes
v->{for(var s:"Baby Daddy Mommy Grandpa Grandma".split(" "))System.out.println(((s+=" Shark")+" doo".repeat(6)+"\n").repeat(3)+s+"!");}

Try it online!

Which JDK version? I'm guessing 8+ (lambdas).

@NoOneIsHere Given the repeat method, it's version 11+

Haskell, 122 113 108 106 104 bytes
s=" Shark";m=do x<-words"Baby Daddy Mommy Grandpa Grandma";("aaa">>x++s++(s>>" doo")++"\n")++x++s++"!\n"

Try it online!

"aaa">>x replicates x 3 times, as "aaa" has length 3.
s>>" doo" replicates " doo" 6 times, as " Shark" has length 6!
2 bytes saved thanks to @Fox
2 bytes saved thanks to @Laikoni

Welcome to the site! We allow just generating a fixed output string as an expression, so you can omit the main=putStr. See also the Haskell rules summary.

Welcome to PPCG. Nice saving with s>>.

@xnor thanks for the links!

@starsandspirals I also recommend taking a look at the Haskell golf tips if you haven't already.

m=(stuff) can just be m=stuff for two fewer bytes

104 bytes by using do-notation: Try it online!

Retina 0.8.2, 77 75 74 bytes

Baby¶Daddy¶MommyGpaGma
G
¶Grand
.+
$&s$&s$&s$&S!
s
S6$*O¶
O
 doo
S
 Shark

Try it online! Explanation:

Baby¶Daddy¶MommyGpaGma
G
¶Grand

Insert the relations on separate lines.
.+
$&s$&s$&s$&S!¶

Expand into four lines.
s
S6$*O¶
O
 doo
S
 Shark

Expand the placeholders.
69 68 bytes in Retina 1:

Baby¶Daddy¶MommyGpaGma
G
¶Grand
.+
$& Shark
.+
3*$($&6*$( doo)¶)$&!

Try it online! Explanation:

Baby¶Daddy¶MommyGpaGma
G
¶Grand

Insert the relations on separate lines.
.+
$& Shark

Append Shark to each.
.+
3*$($&6*$( doo)¶)$&!

Expand into whole verses.

Python 3, 105 97 96 bytes
for x in"Baby","Daddy","Mommy","Grandpa","Grandma":z=x+' Shark';print((z+' doo'*6+"\n")*3+z+"!")

Try it online!
A simple Python 3 solution. (9 bytes saved by Jo King and Quintec)

The parentheses around ' doo'*6 are unnecessary and you have unnecessary whitespace there

What quintec said... 97 bytes

Huh, didn't know you could do lists without [], or that you didn't need a newline for :. Thanks!

@ReverseCold technically where there's no [] it's a tuple not a list, but that's not relevant to this program

96 bytes by setting x+' Shark' to a variable

This seems to work in 2.7 as well?

@uhoh In 2.7 you can get rid of the brackets in the print function and cut it down to 94 bytes

You can shave one more character if you do x+= instead of z=x+ (replacing subsequent uses of z with x)

bash, 78 bytes
printf %s\\n {Baby,Daddy,Mommy,Grand{p,m}a}\ Shark{" `echo doo{,,}{,}`"{,,},!}

TIO
73 bytes if trailing space is allowed
echo '
'{Baby,Daddy,Mommy,Grand{p,m}a}\ Shark{" `echo doo{,,}{,}`"{,,},!}

Perl 6, 79 78 bytes
(<Baby Daddy Mommmy Grandpa Grandma>X~" Shark"X~ |((" doo"x 6)xx 3),'!')>>.say

Try it online!
Pretty simple.
Explanation:
 <...>X~                                  # Combine family members
        " Shark"X~                        # With "Shark" and
                   |((" doo"x 6)xx 3)     # doo repeated 6 times then 3 times
                                     ,'!' # Then !
(                                        )>>.say  # And print each line

Ruby, 82 bytes
%w(Baby Daddy Mommy Grandpa Grandma).map{|a|puts [a+" Shark"]*4*(" doo"*6+?\n)+?!}

Try it online!

It took me a while to understand that you used the "doo" part as array seperators. Good job :)

?\n can be replaced with $/.

///, 124 bytes
/*/$!
//)/Grand//(/Baby//'/Mommy//&/Daddy//%/ doo//$/ Shark//#/a")//"/$%%%%%%
/("("("(*&"&"&"&*'"'"'"'*)p#p#p#pa*)m#m#m#ma$!

Try it online!

JavaScript, 104 bytes
More golfing to follow.
_=>`Baby
Daddy
Mommy
Grandpa
Grandma`.replace(/.+/g,x=>(s=(x+=` Shark`)+` doo`.repeat(6)+`
`)+s+s+x+`!`)

Try It Online!

This technically isn't a valid solution since it neither writes to a file or logs it. Though if you make it a valid solution by wrapping with a console.log(), you can make it not a lambda declaration (only 10 character gain)

@Delioth, returning from a function is perfectly valid on this site. Have a look on Meta for our default I/O rules.

I would generally agree, but this question specifically states that the program "writes the following text to the standard output or an arbitrary file"

PostgreSQL, 162 156 138 bytes
select a||' Shark'||replace(b,'1',repeat(' doo',6))from unnest('{Baby,Daddy,Mommy,Grandpa,Grandma}'::text[])a,unnest('{1,1,1,!}'::text[])b

Ungolfed
select
    a || ' Shark' || replace(b,'1',repeat(' doo',6))
from unnest('{Baby,Daddy,Mommy,Grandpa,Grandma}'::text[]) a
    ,unnest('{1,1,1,!}'::text[]) b

Saved 6 24 bytes thanks to @Nahuel Fouilleul!

use || instead of concat()
use unnest('{foo,bar}'::text[]) instead of regexp_split_to_table('foo,bar')

DB<>fiddle

-6 bytes using ||instead of concat
View on DB Fiddle

select a||' Shark'||replace(b,'1',repeat(' doo',6))from unnest('{Baby,Daddy,Mommy,Grandpa,Grandma}'::text[])a,unnest('{1,1,1,!}'::text[])b

Emotion, 65 bytes
❤

Explanation
 Push literal doo
 Push five copies of the first stack value.
 Collapse all stack values into a string seperated by spaces, then push that string.
 Push literal  Shark
 Push the difference of the second and first stack values.
 Store the first stack value in the a register.
 Push literal Grandma
 Push literal Grandpa
 Push literal Mommy
 Push literal Daddy
❤ Push literal Baby
 Push literal 6
 Push stack values into a list of the size of the first stack value starting with the second stack value.
 Enter an iteration block over the first stack value and push the iteration element register at the begining of each loop.
 Push three copies of the first stack value.
 Push literal 3
 Enter an iteration block over the first stack value.
 Push the value contained in the a register.
 Push the sum of the second and first stack values.
 Print the first stack value, then a newline.
 Ends a control flow structure.
 Push literal  Shark!
 Push the sum of the second and first stack values.
 Print the first stack value, then a newline.
 Ends a control flow structure.

Try it online!

><>, 158 115 bytes
Saved a lot of bytes thanks to Jo King
>4>1-&0'krahS '0l3-.
~ ^oa~<
ooo:?!/1-'ood 'o
\ao'!'^?$6:&~
\!?:o
^'ybaB'
^'yddaD'
^'ymmoM'
^'apdnarG'
^'amdnarG'
;

Try it online! You may also want to paste the code in at fishlanguage.com, where you can see an animation of it swimming running.

121 bytes, mostly through rearranging the baby/daddy/... to multiple lines instead of one line. There's more to golf though

115 bytes

@JoKing Ah, thanks. I tend to assume (mostly from working with BitCycle) that fewer lines are better, but in this case that's not true because of the different string lengths.

Haskell, 97 bytes
unlines[x++s++p|x<-words"Baby Daddy Mommy Grandpa Grandma",p<-[a,a,a,"!"]]
s=" Shark"
a=s>>" doo"

Try it online!
This is an optimization of the Haskell solution by starsandspirals. The new trick is to iterate over the rows of each stanza with an inner loop, and join the lines using unlines, saving the need to explicitly insert newlines.
The suffixes of the four lines are [a,a,a,"!"], where a is " doo" replicated 6 times with a=s>>" doo", where starsandspirals cleverly reuses the six-character-long s=" Shark". Writing [a,a,a,...] looks a bit silly, but I'm not seeing a shorter way.
A list-monad version is the same length but it looks cool.
unlines$(++).(++s)<$>words"Baby Daddy Mommy Grandpa Grandma"<*>[a,a,a,"!"]
s=" Shark"
a=s>>" doo"

Try it online!

C# (Visual C# Interactive Compiler), 153 131 bytes
foreach(var i in"Baby Daddy Mommy Grandpa Grandma".Split()){var a=i+" Shark doo doo doo doo doo doo\n";Write(a+a+a+i+" Shark!\n");}

Thanks to @Destrogio for saving 30 bytes!
Try it online!

133 - Try it online!

whenyouaccidentallylose100endorsementsinnationstates - 123,065 121,716 113,695 100,889 98,554 bytes
The program
I'll golf this later. Done.
I'll golf this more (later) Done.
I'll golf this even more later. DONE.
I'll get the byte count to 5 digits later. YAY.
I'll get the byte count to 4 digits (I don't know if this is possible, but I do know it is impossible to get 3 digits with my current approach).

What the hell is this? I love it

@AdrianZhang A programming language hard to program it. Also, the program looks like it's a person screaming ('AAAAAAAAAAA...')

Both links are dead.

R, 131 122 120 bytes
-9 bytes thanks to Giuseppe
-2 more bytes, also Giuseppe
`?`=c
s="Shark"
for(x in "Baby"?"Daddy"?"Mommy"?"Grandpa"?"Grandma")cat(rep("
"?x?s?rep("doo",6),3)?"
"?x?paste0(s,"!"))

Try it online!
Quite proud of this actually, especially with R being rather poor at handling strings. I started out using cat(sapply(...)), but realized a for loop shaves off a few bytes.
Abusing the "?"=c significantly reduced the amount of parentheses needed.
I also tried to do "*"=rep to repeat the individual lines of the stanzas and the "doos", but that did not shave off any bytes.
111 bytes
Giuseppe and ASCII-only's alternative, (and better) solution that fixes some spacing issues.
write(paste0(rep(c("Baby","Daddy","Mommy","Grandpa","Grandma"),,,4)," Shark",c(rep(strrep(" doo",6),3),"!")),1)

Try it online!

122 bytes

As always, thank you for your wise input @Giuseppe. I should have noticed those golfs

120 bytes

I think you should ask OP whether leading spaces are ok

@ASCII-only I'm pretty certain it's a leading newline, and the additional rules near the bottom say that that is okay. The OP even detailed this concern in the comments, saying "Updated original post. I know you could save a few bytes by doing \n before every stanza (that way you don't have to avoid making a newline at the end), but people already started doing it this way so I think keeping it as is is fair."

Do you not also print two spaces before every line since you're printing a vector :|

@ASCII-only I found a 120 byter that has none of these problems.

@Giuseppe wow, vectorization, nice. I forgot R has nice vectorization like this. 114? also 114?

also 114

@ASCII-only hah, I had found a very similar 115 byter commented below...So naturally we can combine to get this 111 byte monstrosity

Jelly, 42 bytes
“¡N³»ẋ6Wẋ3;”!ṭ€;Y
“¡ʂɓṙṢ®ÑR+£ṭỤṙ»Ḳç€“¤⁾ċ»Y

Try it online!
How?
“¡N³»ẋ6Wẋ3;”!ṭ€;Y - Link 1: make a verse: familyMember; space+animalName
                  -                        e.g. "Baby"; " Shark"
“¡N³»             - dictionary word " doo"
     ẋ6           - repeat 6 times -> " doo doo doo doo doo doo"
       W          - wrap in a list -> [" doo d..."]
        ẋ3        - repeat 3 times -> [" doo d..."," doo d..."," doo d..."]
           ”!     - literal '!' character
          ;       - concatenate    -> [" doo d..."," doo d..."," doo d...","!"]
               ;  - concatenate inputs ["Baby Shark"]
             ṭ€   - tack for €ach  -> [["Baby Shark"," doo d..."],...,["Baby Shark","!"]]
                Y - join with newline characters

“¡ʂɓṙṢ®ÑR+£ṭỤṙ»Ḳç€“¤⁾ċ»Y - Main Link: no arguments
“¡ʂɓṙṢ®ÑR+£ṭỤṙ»          - dictionary words "Baby"+" Daddy"+" Mommy"+" Grandpa"+" Grandma"
               Ḳ         - split at spaces -> ["Baby","Daddy","Mommy","Grandpa","Grandma"]
                  “¤⁾ċ»  - dictionary word " Shark"
                ç€       - call last Link (1) as a dyad for €ach
                       Y - join with newline characters
                         - implicit print

R, 126 125 bytes
cat(paste(rep(c("Baby","Daddy","Mommy","Grandpa","Grandma"),,,4),c(rep("Shark doo doo doo doo doo doo",3),"Shark!")),sep="
")

This doesn't feel as 'clever' as either CT Hall or Sumner18's answers, but by avoiding the overhead of defining variables it comes out smaller.
Try it online!
Edit: Saved 1 byte by using carriage return as per comment by Jonathan Frech

Hello and welcome to PPCG! I have added links to the user's answers you mentioned to better compare your solutions. Congratulations on outgolfing both, could you add a link to an online testing environment for ease of verification?

Thanks for the edit @JonathanFrech. I have now added a link to test the code online (which added a byte to my answer!).

You can use an actual new line instead of \n to bring your byte count one back down again.

125 bytes

Well I've been totally outgolfed; sometimes the simplest option is best. Also highlights how difficult it is to work with strings in R.

115 bytes -- this is quite similar to my suggested edits to Sumner18's answer, but I've worked on improving all three of the R answers, so now all three approaches have been sloshing in my head and I don't know whose to comment on...

Plain TeX, 147 Bytes
\input pgffor\def\D{doo~}\def\d{\D\D\D\D\D\D}\def\S{Shark}\def\y{\x~\S~\d\par}\foreach\x in{Baby,Mommy,Daddy,Grandma,Grandpa}{\y\y\y\x~\S!\par}\bye
Rather disappointing, but I haven't posted a TeX answer in ages.  Loops are very verbose in teX (and looping over strings isn't even built-in so even this is a bit of a stretch)

C (gcc), 123 122 bytes
-1 byte thanks to ceilingcat
#define A" doo doo"
f(i){for(i=20;i--;)printf("%.7s Shark%s\n","GrandmaGrandpaMommy\0 Daddy\0 Baby"+i/4*7,i%4?A A A:"!");}

Try it online!

What are the rules for C? No need for main(), or #include for printf?

@BoBTFish: Not C-specific but generally it is allowed to use any function (name doesn't matter, indeed it can be an unnamed lambda or similar). And languages are defined by their (any) implementation, since this works on gcc (only generates warnings, but compiles fine) it is valid.

I realised the lack of #include was only an error because I was still compiling as C++, but I still couldn't get it to compile without renaming your function to main.

PHP, 104 bytes

foreach([Baby,Daddy,Mommy,Grandpa,Grandma]as$s)echo$t=$s.str_pad($u=" Shark",30," doo"),"
$t
$t
$s$u!
";

Run with php -nr '<code>' or try it online.

103 bytes

R, 139 138 137 bytes
s='Shark';d='doo';cat(paste(rep(c('Baby','Daddy','Mommy','Grandpa','Grandma'),e=4),c(rep(paste(s,d,d,d,d,d,d),3),paste0(s,'!'))),sep='
')

There's probably a better way to do the 'doo's but I wasn't able to get it.
Edit:
Replaced '\n' with actual new line at JDL's suggestion;
Removed trailing newline at  Giuseppe's suggestion.
Try it online

welcome to ppcg! At the very least, replacing the "\n" with a literal newline will save one byte.

Thanks, I did so, and then realized my output was bit off so I updated that, sadly it resulted in more bytes.

I believe you have a trailing newline for an extra byte

05AB1E, 39 38 bytes
”‡ÍÊÐ¢×myîºpaîºma”#„o€·À6×3и'!ª”ã¢”ìâ»

Try it online!
”‡ÍÊÐ¢×myîºpaîºma”                # compressed string "Baby Daddy Mommy Grandpa Grandma"
                  #               # split on spaces
„o€·                              # dictionary string "o do"
    À                             # rotated left: " doo"
     6×                           # string-repeat 6 times: " doo doo doo doo doo doo"
       3и                         # list-repeat 3 times
         '!ª                      # append "!" to that list
            ”ã¢”ì                 # prepend "Shark" to each element of that list
â                                 # cartesian product
 »                                # join by newlines
                                  # implicit output

APL (Dyalog Unicode), 72 bytes (SBCS)
↑,(,∘' Shark'¨'BabyDaddyMommyGrandpaGrandma'(∊⊂⊣)⎕A)∘.,'!',⍨3⍴⊂24⍴' doo'

Try it online!
Explanation:
↑,(,∘' ..'¨'...'(∊⊂⊣)⎕A)∘.,'!',⍨3⍴⊂24⍴' doo'
                                   24⍴' doo'⍝ repeat 'doo' 6 times
                                  ⊂         ⍝ box the 'doo's
                                3⍴          ⍝ make three copies
                           '!',⍨            ⍝ append a `!` at the end
           '...'(∊⊂⊣)⎕A                     ⍝ split the long string on capitals
   ,∘' ..'¨                                 ⍝ append to all family members
                        ∘.,                 ⍝ construct a table where each row is
                                            ⍝ a full verse of the song
↑,                                          ⍝ flatten the resulting verse table

-28 thanks to @Adám
-2 bytes (-14 before; but I did a few golfs before checking the golfed version) thanks to @Razetime

-14

-28

@Adám that's a whole lot smaller, I'll analyze that in a short while. Thanks.

cQuents, 93 89 bytes
|
#20&bk)~" Shark"~(" doo"6,Z,Z,bk)~" Shark!"
:"Baby","Daddy","Mommy","Grandpa","Grandma"

Try it online!
Note that as of posting TIO is not updated to the latest version, so the TIO link may not work.
Explanation
|                               Set delimiter to newline
#20                             n = 20
   &                            Output first n terms in sequence
                                k = 1
                                First term is
    bk)~" Shark"                 kth term from the third line concatenated to " Shark"
                ~(" doo"6,        concatenated to " doo" repeated 6 times
Z,Z,                            Second and third terms equal the first term
    bk)~" Shark!"               Fourth term is the kth term from the third line concatenated to " Shark!"
                                k += 1, restart

Third line                      5 terms, each a string

JavaScript (Node.js), 132 bytes
Probably very golf-able. Generates the "doo doo" line, then creates three of those with the "!" line after, and repeats this for each shark.
a=""
c=" doo"
for(b of["Baby","Daddy","Mommy","Grandpa","Grandma"]){b+=" Shark"
t=b+c+c+c+c+c+c+"\n"
a+=t+t+t+b+"!\n"}console.log(a)

Try it online!

A slightly changed solution in Javascript, no gain though:
a="";c=" doo";for(b of["Baby","Daddy","Mommy","Grandpa","Grandma"]){b+=" Shark";t=b+c.repeat(6)+"\n";a+=t+t+t+b+"!\n"}console.log(a)

Japt -R, 55 bytes
Pretty naïve first pass.
`baß'adÝcomæ²T\`èT\`µ`qi Ë'!i4Æ` Srk`iDhDÎuÃqRi6ç` ºo

Test it

Farm, 1157 897† bytes
-260 bytes: apparently only cock a doodle doo needs spaces..
No sharks on my farm:
cock a doodle doomoocotmoobzzcoucoumewmewmewmewmewmewmewgobblehihihimoopiuarfarfarfarfarfarfarfrouuuleomoopiumoosquealhihihimewmooleoarfarfarfrouuuleomoomoocotmoopiuarfarfarfmooleoarfarfarfarfmoomoocoucouarfarfarfssscoinsssgruntcoinblatcoinssscoinblatcoinssscoinblatmoosssgruntmooblatarfarfarfarfarfarfsssmoogruntmoogruntmoogruntgruntcoincoincoinmewblatmoosssmooblatmoosssmooblatcoinmewblatcoinsssgruntcoinblatcoinssscoinblatcoinssscoinblatmoosssgruntmooblatcotarfgruntsssmewblatmoosssmooblatmoogobblesquealmewmoopiuarfmoopiumooroararfmooarfarfarfarfarfarfarfarfarfarfmoohihihimooarfarfmooarfarfarfmoopiumoosssmewmooarfcoinblatroararfarfarfmoomoohihihimooleoarfarfrouuuleomooleomooleoarfarfmooarfarfarfarfarfarfarfarfarfmoomoohihihipiumooleoarfarfarfmoopiuarfarfarfmoomewmoopiumooleoarfarfarfarfarfmooroararfarfarfarfarfarfmooarfarfarfarfarfarfarfarfarfarfmoohihihimoomewmewmewsssmooblathihihihowl

Try it online!

†: Could be 9 less by using cocorico over cock a doodle doo..

Why not use cocorico then :P

@ASCII-only: Because I found the language by searching doo on esolangs, lol

The self-graduating add-on for PPCG leaderboard thinks that this is 1 byte. Can you change the 1 to see bottom

Javascript, 125 123 bytes
['Baby','Daddy','Mommy','Grandpa','Grandma'].flatMap(x=>[...[,,,].fill(' doo'.repeat(6)),'!'].map(y=>x+' Shark'+y)).join`
`

Try it online!

Stax, 43 bytes
ÇÉ╕µM%╠2'§t╪╝½ôòn=n╢/╬╦Φ▲Vêø■T⌂g^N┴W.ìC↕ƒ·Φ

Run and debug it

PHP, 153 147 bytes
<?php $s='Shark';$d=str_pad('',23,'doo ');foreach(explode(' ','Baby Daddy Mommy Grandpa Grandma')as$a){echo str_repeat("$a $s $d\n",3),"$a $s!\n";}

Thanks to @manatwork for saving 6 bytes by pointing out str_pad('',23'doo '); is shorter than rtrim(str_repeat('doo ',6));
Try it online!

Unfortunately even $d='doo doo doo doo doo doo' is shorter than that rtrim()+str_repeat() combination. :( But fortunately $d=str_pad('',23,'doo ') is even shorter. For more optimization tips, see Tips for golfing in PHP.

@manatwork Thanks for pointing that out, I've updated the post to reflect

In meantime found some time to play a bit more: Try it online!

113 bytes. Welcome to PPCG!

Oop, didn't see your last comment before posting mine, @manatwork.

109 bytes

JavaScript (134 126 bytes)
-2 bytes thanks to Stephen!
-6 bytes thanks to mgthomas99!
["Baby","Daddy","Mommy","Grandma","Grandpa"].forEach(a=>console.log((a+" shark"+" doo".repeat(6)+"\n").repeat(3)+a+" Shark!"))

JS Fiddle

Can save two bytes: a + " -> a+"

Wow I was working on a JS solution and barely managed to get to 170 bytes.  Your use of repeat is genius!

You can save 2 bytes by removing the parentheses around the arrow function parameters (so that (a)=> becomes a=>). You can save another 2 bytes by removing the braces around the arrow function body. I'm also not certain you need the explicit newline at the end of the console.log statement, and removing that should save you another 2 bytes.

The first shark should be capitalised

You can save 1 byte by converting the array to a single string with separator characters, and then splitting on those separator characters, and another 4 bytes by changing forEach to map (if you run directly in console, it could print out the return of the map, which is an array of undefined's, but if you run from a file, it doesn't print out that array) "Baby|Daddy|Mommy|Grandma|Grandpa".split\|`.map(a=>console.log((a+" shark"+" doo".repeat(6)+"\n").repeat(3)+a+" Shark!"))`

jq, 87 characters
" Shark"as$s|("Baby Daddy Mommy Grandpa Grandma"/" ")[]|(.+$s+" doo"*6+"\n")*3+.+$s+"!"

Sample run:
bash-4.4$ jq -nr '" Shark"as$s|("Baby Daddy Mommy Grandpa Grandma"/" ")[]|(.+$s+" doo"*6+"\n")*3+.+$s+"!"'
Baby Shark doo doo doo doo doo doo
Baby Shark doo doo doo doo doo doo
Baby Shark doo doo doo doo doo doo
Baby Shark!
Daddy Shark doo doo doo doo doo doo
Daddy Shark doo doo doo doo doo doo
Daddy Shark doo doo doo doo doo doo
Daddy Shark!
Mommy Shark doo doo doo doo doo doo
Mommy Shark doo doo doo doo doo doo
Mommy Shark doo doo doo doo doo doo
Mommy Shark!
Grandpa Shark doo doo doo doo doo doo
Grandpa Shark doo doo doo doo doo doo
Grandpa Shark doo doo doo doo doo doo
Grandpa Shark!
Grandma Shark doo doo doo doo doo doo
Grandma Shark doo doo doo doo doo doo
Grandma Shark doo doo doo doo doo doo
Grandma Shark!

Try it online!

Jelly, 51 bytes
;“¤⁾ċ»;“¡N³»ẋ6¤;”¶ẋ3;;“ß<Ė»
“þɗ“¡þ"“£H$“æf⁵“æeⱮ»Ç€Y

Try it online!
Jelly isn't the best for string manipulation. Still pretty good.
If you expand out the strings to their ungolfed form, the code looks like this:
;“ Shark”;“ doo”ẋ6¤;“¶”ẋ3;;“ Shark!”
“Baby“Daddy“Mommy“Grandpa“Grandma”Ç€Y

(The string compression was done using user202729's compressor).
;“ Shark”;“ doo”ẋ6¤;“¶”ẋ3;;“ Shark!”   Helper Link; take a string and format it into a stanza
;“ Shark”                              Append " Shark" to the string
         ;                             Join
                  ¤                    Previous links as a single nilad
          “ doo”                       " doo"
                ẋ6                            repeated 6 times
                   ;“¶”                Append a newline
                       ẋ3              Repeat 3 times
                         ;             Append the string
                          ;“ Shark!”   Append " Shark!"
“Baby“Daddy“Mommy“Grandpa“Grandma”Ç€Y  Main link
“Baby“Daddy“Mommy“Grandpa“Grandma”     ["Baby", "Daddy", "Mommy", "Grandpa", "Grandma"]
                                  Ç€   For each of these words, format it into the stanza with that family position
                                    Y  Join by newlines

Kotlin 121 bytes
"Baby Daddy Mommy Grandpa Grandma".split(" ").map{(println(("${"$it Shark${" doo".repeat(6)}\n".repeat(3)}$it Shark!")))}

Try it online!

Befunge-93, 527 bytes
vv          <<
3v       v,<           v   v     v
0>" ybaB">:| p
<v         <^6#
         v,< 1
>>"krahS">:| "
 v06$      <0<v,,"!"*25
        v,<>^"$v       <
 >"ood ">:|^_^3         v,<
 ^0_v#:-1$< : \>" yddaD">:|
^   >$52*,1-^ "^0$ <      >
^             v     v      < v,<>
>">":62*1p62*#"1+1p^>" ymmoM">:|
^p-1:*27"1"p61<     0    >     >^
v p1-1*46">"p6<     $     v      <v,<
>"6"72*:p    #p     ^     >"dnarG">:|
v     p1*39">"<          ^  ,,,"pa "<
>"v"72*82*p            >$0^
v   p*28*48"m"<
>"@"72*6p              ^

Try it online!
I didn't really try to golf it much, I just wanted it to work. It does, and I'm pretty proud of it. I used the "p" command heavily to reuse a lot of code.

J, 85 bytes
echo('Shark'(,&'!',~(24$' doo')(3#,:)@,~])@,~]);.2'Baby Daddy Mommy Grandpa Grandma '

Try it online!
Note: This assumes a blank line between stanzas is ok.  If that's not the case, prepending ,/ to my solution for +2 bytes.

Attache, 79 bytes
$Baby'$Daddy'$Mommy'$Grandpa'$Grandma+" Shark":>Print@{(_+" doo"*6+lf)*3+_+"!"}

Try it online!
An attempt at compressing the above iteration array is NTS@N=>Split[S@FromBase[Ords@")!-ZOW]NE.kK3(*F(a3\\z6fXD_\\yEM"-32,95],"00"], which is significantly longer than the trivial encoding above. Compressing the string using base conversion in its entirety would likely come out to be longer.
Alternatives
81 bytes: Print@{(_+" doo"*6+lf)*3+_+"!"}=>($Baby'$Daddy'$Mommy'$Grandpa'$Grandma+" Shark")
82 bytes: Output!{(_+" doo"*6+lf)*3+_+"!"}=>($Baby'$Daddy'$Mommy'$Grandpa'$Grandma+" Shark")
86 bytes: Output!(""'3&(" doo"*6+lf)'"!")&Join=>($Baby'$Daddy'$Mommy'$Grandpa'$Grandma+" Shark")
87 bytes: Output!(""'3&(" doo"*6+lf)'"!")&Join@`+&" Shark"=>$Baby'$Daddy'$Mommy'$Grandpa'$Grandma

F# (.NET Core), 179 bytes
["Baby";"Daddy";"Mommy";"Grandpa";"Grandma"]|>Seq.map(fun i->([0..2]|>Seq.map(fun _->i+" Shark doo doo doo doo doo doo")|>String.concat "\n")+"\n"+i+" Shark!")|>String.concat "\n"

Try it online!
No input, export to a string and to std output in a console.
145 bytes
for i in["Baby";"Daddy";"Mommy";"Grandpa";"Grandma"]do(for _ in[0..2]do printfn"%s"(i+" Shark doo doo doo doo doo doo"));printfn"%s"(i+" Shark!")

Try it online!
No input, export to std output

F# (.NET Core), 160 156 bytes
let c,r,s=String.concat,List.replicate," Shark"
let p n=r 3(c" "(n+s::r 6"doo"))@[n+s+"!"]
["Baby";"Daddy";"Mommy";"Grandpa";"Grandma"]|>Seq.collect p|>c"
"

Try it online!
And based on @aloisdg version, I get this one:
F# (.NET Core), 130 129 bytes
let p,d=printfn"%s Shark%s"," doo doo"
for i in["Baby";"Daddy";"Mommy";"Grandpa";"Grandma"]do(for _ in"123"do p i (d+d+d));p i"!"

Try it online!
Gaining 1 more char by changine [0..2] by "123" wich is also a sequence of 3 items...

groovy, 96 bytes
'Baby Daddy Mommy Grandpa Grandma'.split().any{n="$it Shark";println((n+" doo"*6+'\n')*3+n+'!')}

Try it online!

Protip: esc -> s -> g on the TryItOnline page for a well formatted post

close

also close

brainfuck, 627 593 573 bytes
Initialise Array with "Baby\0Daddy\0Mommy\0Grandpa\0Grandma"
Loop runs 71 times
++[++++++++++++++++++
    Get array cells to approximately correct values
    >>>+>>+++++>>+++++>>-->>>>+>>+++++>>+++++>>+++++>>-->>>>+>>-->>-->>-->>-->>>>+>>-->>+++++>>-->>+++++>>-->>+++++>>>>+>>-->>+++++>>-->>+++++>>-->>+++++
    [[<<]<<]>
]
Finish getting cells to correct values
>>>---->>->>>>++++++++>>+>>-->>->>++>>++>>++++++++>>+>>+++++++>>-->>---->>---->>++++++++>>+>>+>>+>>->>--->>++>>->>->>+>>+>>+>>->>--->>++>>---->>-
Inject ones between each cell in the array
[-<+<]>[>>]+

Initialise an exclamation mark; newline; and the string " Shark"
>>>+++++++++++[+++++++
    >------->+>>+>----->+++>+++>---->+++
    <<<<<<<<<
]
>->-->>--->++>->-------->-->++
[<]
Go to the end of the "Baby" Array to loop
<<<<<<[
    >>>
    Loop 3 times
    +++[-
        Go to the first value of the baby array
        <<<[<<]>>>
        Print the word out
        [.>>]
        Go to the shark array
        >[>>]>>>>>
        Print " Shark"
        [.>]
        <[<]
        Loop 6 times
        ++++++[-
            Print a space
            >.
            Change the 'a' in " Shark" to a 'd' and print
            >>>+++.---
            Change the 'r' in " Shark" to an 'o' and print twice
            >---..+++
            <<<<<
        ]
        Print newline
        <<.
        <
    ]
    Go to start of baby array
    <<<[<<]>>
    Print and consume the first string in the array
    ->[.[-]>->]
    Go to shark string
    >[>>]>>>>>
    Print " Shark"
    [.>]
    <[<]
    Print "!\n"
    <.<.
    <<<<
]

-20B thanks to Jo King
Try it online!

T-SQL, 151 bytes
SELECT REPLACE(a.value+' Shark'+b.value,'Q',REPLICATE(' doo',6))
FROM STRING_SPLIT('Baby,Daddy,Mommy,Grandpa,Grandma',',')a,STRING_SPLIT('Q,Q,Q,!',',')b

Line break for readability only.
SQL's built-in function names are annoyingly long.
STRING_SPLIT works in SQL 2016 and later.
Order isn't 100% guaranteed without an ORDER BY, but this seemed to work in my testing.

It seems sql answers are not popular, very nice answer. Which means a lot comming from me

Thanks, @t-clausen.dk!

Japt -R, 58 57 bytes
`BabysDaddysMommysGÎÀpGÎÀµ`qÅË±` Srk` +` ºo`³²+R ³+D+'!

Run it online

Perl 5, 84 bytes
print (map{join(" doo"x6,("\n$_ Shark")x4),"!"}qw(Baby Daddy Mommy Grandpa Grandma))

Try it online!

73 bytes

68 bytes

VBA (Excel), 152 118 bytes
-34 bytes. Thanks @TaylorScott
Using Immediate Window.
a=Split("Baby Daddy Mommy Grandpa Grandma"):b=" Shark":c=" doo":For d=0To 19:?a(Int(d/4))b &IIf((d+1)Mod 4=0,"!",Join(Split(String$(6,"."),"."),c)):Next
a=Split("Baby Daddy Mommy Grandpa Grandma"):b=" Shark":For d=0To 19:?a(d\4)b;IIf((d+1)Mod 4,[Rept(" doo",6)],"!"):Next

You should use integer division instead of casting an int over division - so Int(d/4) goes to d\4 , you can rearrange the arguements of the IIf statement to get rid of the =0 and then you can convert that really nifty join split statement with a Rept statement. All together this becomes a=Split("Baby Daddy Mommy Grandpa Grandma"):b=" Shark":For d=0To 19:?a(d\4)b;IIf((d+1)Mod 4,[Rept(" doo",6)],"!"):Next for 118 Bytes

Totally forgot Rept function lol. Your answer is way better than mine you should've post it as your own answer. Anyways, thanks for cutting off huge bytes to my wall of code. lol. d\4 <-- Didn't know this until now. Thanks! :D

I get far more joy out of helping others get better with VBA, than I do writing it myself - Cheers

Clean, 134 bytes
import StdEnv,Text
r=repeatn
f=join"\n"[e+" Shark"+concat s\\e<-split" ""Baby Daddy Mommy Grandpa Grandma",s<-r 3(r 6" doo")++[["!"]]]

Try it online!

Underload, 93 89 bytes
(Grandma)(Grandpa)(Mommy)(Daddy)(Baby)(~( Shark)*:( doo)::**:**(
)*::**S(!
)*S):^:^:^:^:^

Since Underload is really good at duplicating and concatenation with strings, I decided to give this a go.
Saved 4 bytes by re-arranging things.
Try it online!
Explanation
(Grandma)  Pushes 'Grandma'
(Grandpa)  Pushes 'Grandpa'
(Mommy)  Pushes 'Mommy'
(Daddy)  Pushes 'Daddy'
(Baby)   Pushes 'Baby'
(  Add the next bit of code to the stack
~  Swaps so the name of the Shark (eg: Baby) is on the top of the stack
( Shark)  Pushes ' Shark' to the stack
*  Concatenates ' Shark' to the name of the Shark
:  Duplicates the top of the stack
( doo)  Pushes ' doo'
::**:*  Turns it into ' doo doo doo doo doo doo'
*  Concatenates it to the '[name] Shark'
(<Newline>)*  Concatenates a newline to the string, making it '[Name] Shark doo doo doo doo doo doo[Newline]'
::**   Duplicates it twice
S  Outputs the first three lines of the stanza
(![Newline])*S Concatenates '![Newline]' to the '[Name] Shark' string and prints it
)  Ends the code being added to the stack
:^:^:^:^:  Runs the code in the bracket 5 times, for the 5 different stanzas

Babylang, 2866 bytes
aaag aaag gagu aaag aaag aaag aaag aaag aaag aaag aaag aaag aaag aaag aaag aaag aaag aaag aaag aaag aaag gaga gaga gaga aaag gaga gaga aaag aaag aaag aaag aaag gaga gaga aaag aaag aaag aaag aaag gaga gaga uuug uuug gaga gaga gaga gaga aaag gaga gaga aaag aaag aaag aaag aaag gaga gaga aaag aaag aaag aaag aaag gaga gaga aaag aaag aaag aaag aaag gaga gaga uuug uuug gaga gaga gaga gaga aaag gaga gaga uuug uuug gaga gaga uuug uuug gaga gaga uuug uuug gaga gaga uuug uuug gaga gaga gaga gaga aaag gaga gaga uuug uuug gaga gaga aaag aaag aaag aaag aaag gaga gaga uuug uuug gaga gaga aaag aaag aaag aaag aaag gaga gaga uuug uuug gaga gaga aaag aaag aaag aaag aaag gaga gaga gaga gaga aaag gaga gaga uuug uuug gaga gaga aaag aaag aaag aaag aaag gaga gaga uuug uuug gaga gaga aaag aaag aaag aaag aaag gaga gaga uuug uuug gaga gaga aaag aaag aaag aaag aaag gagu gagu gugu gugu guga gugu gugu guga gaga guga gaga gaga gaga uuug uuug uuug uuug gaga gaga uuug gaga gaga gaga gaga aaag aaag aaag aaag aaag aaag aaag aaag gaga gaga aaag gaga gaga uuug uuug gaga gaga uuug gaga gaga aaag aaag gaga gaga aaag aaag gaga gaga aaag aaag aaag aaag aaag aaag aaag aaag gaga gaga aaag gaga gaga aaag aaag aaag aaag aaag aaag aaag gaga gaga uuug uuug gaga gaga uuug uuug uuug uuug gaga gaga uuug uuug uuug uuug gaga gaga aaag aaag aaag aaag aaag aaag aaag aaag gaga gaga aaag gaga gaga aaag gaga gaga aaag gaga gaga uuug gaga gaga uuug uuug uuug gaga gaga aaag aaag gaga gaga uuug gaga gaga uuug gaga gaga aaag gaga gaga aaag gaga gaga aaag gaga gaga uuug gaga gaga uuug uuug uuug gaga gaga aaag aaag gaga gaga uuug uuug uuug uuug gaga gaga uuug gagu uuug gugu aaag gugu guga gaga gagu gaga gaga guga aaag gaga gaga gaga aaag aaag aaag aaag aaag aaag aaag aaag aaag aaag aaag gagu aaag aaag aaag aaag aaag aaag aaag gaga uuug uuug uuug uuug uuug uuug uuug gaga aaag gaga gaga aaag gaga uuug uuug uuug uuug uuug gaga aaag aaag aaag gaga aaag aaag aaag gaga uuug uuug uuug uuug gaga aaag aaag aaag gugu gugu gugu gugu gugu gugu gugu gugu gugu guga gaga uuug gaga uuug uuug gaga gaga uuug uuug uuug gaga aaag aaag gaga uuug gaga uuug uuug uuug uuug uuug uuug uuug uuug gaga uuug uuug gaga aaag aaag gagu gugu guga gugu gugu gugu gugu gugu gugu gagu gaga gaga gaga aaag aaag aaag gagu uuug gugu gugu gugu gagu gugu gugu guga gaga gaga gaga gagu guuu gaga gaga guga gaga gagu gaga gaga guga gaga gaga gaga gaga gaga gagu guuu gaga guga gugu gagu gugu guga aaag aaag aaag aaag aaag aaag gagu uuug gaga guuu gaga gaga gaga aaag aaag aaag guuu uuug uuug uuug gaga uuug uuug uuug guuu guuu aaag aaag aaag gugu gugu gugu gugu gugu guga gugu gugu guuu gugu guga gugu gugu gugu gagu gugu gugu guga gaga gaga uuug gaga gagu guuu gagu uuug guga gaga uuug gaga guga gaga gagu gaga gaga guga gaga gaga gaga gaga gaga gagu guuu gaga guga gugu gagu gugu guga gugu guuu gugu guuu gugu gugu gugu gugu guga

GolfScript, 70 bytes
"Baby
Daddy
Mommy
Grandpa
Grandma"n/{" Shark"+" doo"6*n++...-25<"!"n}/

Try it online!
Explanation:
"Baby
Daddy
Mommy
Grandpa
Grandma"n/                                       Push shark names, then split by newline
          {                               }/     For each name:
           " Shark"+                                 Concatenate with Shark
                    " doo"6*n++                      add doo * 6 then newline
                               ...                   Duplicate line 3 more times
                                  -25<               Cut off the "doo"s
                                      "!"n           Add "!"

Rockstar, 151 125 bytes
cut "Baby,Daddy,Mommy,Grandpa,Grandma" in N with ","
while N
roll N in S
let L be S+" Shark"+" doo"*6+"
"
say L*3+S+" Shark!"

Try it here (Code will need to be pasted in)

Vyxal, 48 bytes
`÷Ċ ₈Ȧ Mummy ∆ƛpa ∆ƛma`⌈` Ẏ꘍`+ƛ3(` doo`6*+,)\!+,

Try it Online!
A mess.
`...`⌈                         # Names, split on newlines
      `...`+                   # Append ' Shark' to each
            ƛ                  # Foreach...
             3(          )     # Three times
               ` doo`6*+,      # Append six doos and output
                          \!+, # Append a ! and output

That uses and outputs "Mummy Shark", not "Mommy Shark" as in the original post.

Wolfram Language (Mathematica), 95 bytes
Do[Print[a," Shark"<>If[i>3,"!",Table[" doo",6]]],{a,{Baby,Daddy,Mommy,Grandpa,Grandma}},{i,4}]

Try it online!

Emacs Lisp, 177 bytes
(defmacro w()`(princ(concat i" Shark doo doo doo doo doo doo\n")))
(defmacro z()`(princ(concat i" Shark!\n")))
(loop for i in'("Baby""Daddy""Mommy""Grandpa")do(and(w)(w)(w)(z)))

C# (Visual C# Interactive Compiler), 139 bytes
"Baby Daddy Mommy Grandpa Grandma".Split().ToList().ForEach(x=>{string a=" doo",m=x+$" Shark{a+a+a+a+a+a}\n";Write(m+m+m+x+" Shark!\n");});

Try it online!
Any thoughts on improvements?  I started aiming for a Linq-based solution with a SelectMany but the deferred execution failed me, along with string.join and return x; being quite verbose syntax

137 :P (2x3 = 5 occurrences is shorter than 6)

134

131 which is basically the same as the other solution

132, close

also 132

Another 132 with foreach

Swift 4, 149 bytes
var s=" Shark";for i in["Baby","Daddy","Mommy","Grandpa","Grandma"]{for _ in 0...2{print(i+s+(0..<6).map({_ in" doo"}).reduce("",+))};print(i+s+"!")}

Try it online!

126

119

C (compiled with VC++ (Visual Studio 2017)) 536Bytes
#include "stdafx.h"
#define d "doo "
#define p(x) printf(x);
#define n p("\n")
#define b p(f[i])p(" Shark ")
#define l(x,y) for(int x=0;x<y;x++)
void main(){const char*f[]={"Baby","Daddy","Mommy","Grandpa","Grandma"};l(i,5){l(k,3){b;l(j,6)p(d)n}b;p("\b!\n")}}

this is my naive try: it started from the "good version" where everything is done the neat and tidy way and i just removed the blanks, semicolons where possible and curly braces if possible. i changed main from int to void in order to be able to leave out the return Statement in the end
if using a different Compiler (say gcc) the stdafx.h can be ommitted (visual Studio throws an error though (or i just dont know how to do it better...))
although then the use of printf means you either have to include stdio.h instead (=1byte win) or you have to use a Compiler flag to add this to the build path although not mentioned in the Code....
if its no dealbreaker if the exclamation mark is one space away from Baby Shark then the \b can be ommitted (=2 Byte win)

removing the space between include and " makes a 1byte win. and removing the space between ) and for makes another  Maybe you can squeeze out a bit more by modifing the l makro to make curly braces and therefor take one Argument more (=the loopbody)

Would also work with a non const char array, no?

i used to compile that with visual studio and that throws an error if not. maybe other compilers aint that strict

Wolfram Language (Mathematica), 145 bytes
Nothing special, still thinking of a shorter method.
a={"Baby","Daddy","Mommy","Grandpa","Grandma"};c=" Shark";b=c<>StringJoin@Table[" doo",6];Do[Do[Print[a[[i]]<>b],3];Print[a[[i]]<>c<>"!"];,{i,5}]

Try it online!

141?

137?

116?

btw, join works instead of stringjoin

105? also join works only because you <> right after

also 105

95?

also 95 but stolen from Haskell answer

@ASCII-only nice improvements. I think that you can take credit for those though, you went a long way from where I started!

:P well I still did base it off your solution (I barely know Mathematica), plus as you can probably see I was mostly just reordering things

ink, 114 113 110 bytes
-(h)~temp t="{Baby|Daddy|Mommy|Grand{ma|pa}} Shark"
-(l){t}<>{l%4<1:
!
{h>5:->END}->h
}
-(d)\ doo{d%5:->d}
->l

Try it online!
Explained
-(h)                                                   // A gather, we can jump here and keep track of how many times we've visited.
~temp t="{Baby|Daddy|Mommy|Grand{ma|pa}} Shark"        // The sequence takes on the next value each time it's visited, and we can nest them. Save into local variable t
-(l){t}<>{l%4<1:                                       // Print t and no newline, then if the number of times we've been here is divisible by 4...
!                                                      // Print an exclamation mark
{h>5:->END}->h                                         // Go to h, or halt if we've already been there more than 5 times
}
-(d)\ doo{d%5:->d}                                     // Print " doo" until we've done it a number of times that is a multiple of 5
->l                                                    // Go to l to print the next line

Wren, 110 108 bytes
Fn.new{["Baby","Daddy","Mommy","Grandpa","Grandma"].map{|i|((i=i+" Shark")+" doo"*6+"
")*3+i+"!"}.join("
")}

Try it online!


text:
Arbitrary Interval Ruler
Make a program that takes a length and list of intervals and outputs a ruler of that length with longer ticks for each interval using the line drawing characters ┌ ┬ ┐ │ ╵

The first row of the output should begin with the tick for 0 with ┌ and end with a tick for the length with ┐, with a ┬ being used for every character in between. There will be a total of length + 1 line drawing characters in this first row.
A tick should be lengthened vertically by half-character increments using ╵ and │ based on the input intervals.
Intervals are listed from smallest to largest, relative to the interval before it. To elaborate:

The first interval tells how many base ticks (the first row - one character per tick) are in the second-smallest interval (the smallest interval being 1). For example, [3] will lengthen every third tick by a half-character.
The second and subsequent intervals are in terms of the next smallest interval. For example [3, 5] will lengthen every 15th base tick by a full character and [3, 5, 2] will lengthen every 30th base tick by a character and a half.
A sub-interval of 1 is valid and effectively means that the last interval lines are lengthened by a full character instead of a half-character.

The example test cases should help to clarify how this works.

Examples/Test Cases
3, []:
┌┬┬┐

9, [3]:
┌┬┬┬┬┬┬┬┬┐
╵  ╵  ╵  ╵

30, [5, 2]:
┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐
│    ╵    │    ╵    │    ╵    │

32, [4, 2, 2, 2]:
┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐
│   ╵   │   ╵   │   ╵   │   ╵   │
│               ╵               │

48, [5, 3, 2]
┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐
│    ╵    ╵    │    ╵    ╵    │    ╵    ╵    │
╵                             ╵

24, [7, 3]
┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐
│      ╵      ╵      │

17, [3, 2, 1]
┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐
│  ╵  │  ╵  │  ╵
╵     ╵     ╵

1, [23, 19, 13, 11, 7, 5, 3, 2, 1]
┌┐
│
│
│
│
╵

Other Rules/Notes

Input and output can use any convenient format
The ruler doesn't have to end on a major tick
The interval list may be empty
The zeroth tick is always within all intervals.
You may assume the ruler length and intervals will always be a positive integers less than 120
Trailing whitespace is fine, but leading whitespace is not.
Any fixed-single-wide space is allowed as a spacing character if you, for some reason, want to use something other than ASCII spaces.

Happy Golfing!

For output, can I print the first row, then return a list of columns?

@EmbodimentofIgnorance, I'm gonna say no to that. Output should be consistent.

Can we take the box-drawing characters from a single-byte encoding (provided one exists containing the ones required)?

"any convenient format" - can we accept the interval list in reverse order?

@ngn: I don't see why not. If that somehow helps you, go for it.

JavaScript (Node.js), 123 bytes
l=>g=([p,q,...t],h='┌'.padEnd(l,'┬')+`┐
`)=>p?h+g(t,h.replace(/\S/g,c=>'╵│ '[c>'╴'||++i%p?2:i/p%q<1|0],i=-1)):h

Try it online!
Use this function as f(20)([5, 2]).

Thanks Arnauld, saves 4 bytes.

Perl 6, 130 122 102 92 bytes
-10 bytes thanks to nwellnhof!
{'┌'~'┬'x$^a-1~'┐',|map {[~] <<' '╵ │>>[:1[$_ X%%@_]for 0..$a]},batch [\*] @^b: 2}

Try it online!
Ah yes, much shorter than my previous method. This is an anonymous code block that returns a list of lines.
Explanation:
{                                                   }   # Anonymous code block
 '┌'~'┬'x$^a-1~'┐',     # Return the first line
 |[\*] @^b          # Get the cumulative product of the input list
              .batch(2) # And split it into pairs
  .map:{                                      }  # Map each pair to
                                    for 0..$a    # For each interval
                        :1[$_ X%%@_]    # Whether it is divisible by none of the pair, one of the pair, or both
            <<' '╵ │>>[                     ]      # Map to a list of characters
        [~]        # And join

Dyalog APL, 66 64 58 52 bytes
{'┌┐'@0⍵@0⍉('┬│',⎕UCS 9589)/⍤1⍨1,⍉0 2⊤⊥¨⍨0=(⍵+1)⍴⍳⍺}

Try it online!
¯2 ¯8 ¯14 bytes thanks to ngn!

∊'┌'(1↓⍵⍴'┬')'┐' -> '┌┬┐'/⍨2⍵2-1

@ngn thanks! These are the kinds of golfs that are pretty understandable but i never know to anticipate or know uses of

finally, i managed to shorten the rightmost part a little...  +⌿0=(×\⍺)∘.|⍳1+⍵ -> ⊥¨⍨0=(⍵+1)⍴⍳⌽⍺. accepting ⍺ in reverse order has been explicitly allowed now, so you can also remove the ⌽

('┌┬┐'/⍨2⍵2-1) -> '┌┬┐'[2,⍨×⍳⍵]

or even better: ('┌┬┐'/⍨2⍵2-1)⍪⍉ -> '┌┐'@0⍵@0⍉'┬',

or even more: ('┌┬┐'/⍨2⍵2-1)⍪⍉('│',⎕UCS 9589)/⍤1⍨ -> '┌┐'@0⍵@0⍉('┬│',⎕UCS 9589)/⍤1⍨1,

@ngn ooh smart to unify the first row, thanks!

Now to explain it…

Python 3, 173 172 bytes
def f(w,n):
 print('┌'+'┬'*~-w+'┐');R=r=range(w+1)
 for i,j in zip(*[iter(n+[0])]*2):a=r[::i];r=j*[0]and a[::j];print(''.join(' ╵│'[(v in a)+(v in r)]for v in R))

Try it online!

05AB1E, 51 bytes
ÝεyIηPÖO2‰•5·W4•2äç×SI¯Qiεõ}}•áΣ=Yô•3äçy¹QyĀ+èš}ζJ»

Not too happy with the I¯Qiεõ}} as work-around for empty input-lists.. And can definitely be golfed at some other parts as well..
NOTE: Uses compressed integers converted to the required characters, because using the required characters directly means I'll have to count the entire program in UTF-8, increasing it by too much for all 05AB1E's builtin characters as well.
Try it online or verify all test cases.
Explanation:
Ý             # Create a list in the range [0, first (implicit) input-integer]
 ε            # Map each value `y` to:
   Iη         #  Get the prefixes of the second input-list
     P        #  Get the product of each prefix
  y   Ö       #  Check for each if its evenly dividing the value `y`
       O      #  Take the sum of that
        2‰    #  And then the divmod 2
  •5·W4•      #  Push compressed integer 94749589
        2ä    #  Split into two equal-sized parts: [9474,9589]
          ç   #  Convert each to a character: ["│","╵"]
           ×  #  Repeat each based on the divmod 2 result
            S #  And convert it to a flattened list of characters
  I¯Qi   }    #  If the second input-list was empty:
      εõ}     #   Map each list to an empty string
              #   (for some reason `€õ` doesn't work here..)
  •áΣ=Yô•     #  Push compressed integer 948495169488
         3ä   #  Split into three equal-sized parts: [9484,9516,9488]
           ç  #  Convert each to a character: ["┌","┬","┐"]
  y¹Q         #  Check if the value `y` is equal to the first input-integer
              #  (1 if truthy; 0 if falsey)
     yĀ       #  Check if the value `y` is NOT 0 (1 if truthy; 0 if falsey)
       +      #  Add both checks together
        è     #  Use it to index into the list ["┌","┬","┐"]
         š    #  And prepend the result in front of the other characters
 }ζ           # After the map: zip/transpose; swapping rows and columns (with space filler)
   J          # Join every inner list together to a single string
    »         # Join the lines with newline delimiter (and output implicitly)

See this 05AB1E tip of mine (section How to compress large integers?) to understand why •5·W4• is 94749589 and •áΣ=Yô• is 948495169488.

×S can be и

@MagicOctopusUrn I first thought so too at first, but it doesn't unfortunately (just try it with one of the other test cases with a non-empty list). sиS does work, but unfortunately it's a byte longer instead of shorter. It's because the integers are on the stack first, and the strings after. With × it doesn't matter whether it's int,string or string,int, but with и it expects string,int.

Oh I see, man this one was confusing hah. Nice job on it, going to be honest I spent 10 minutes just trying to figure out what was going on, missed that tidbit about и! That'll be good to know in the future, I hadn't seen it used before one of your other answers.

Charcoal, 50 bytes
≔ＥηΠ…η⊕κη⪫┐┌×┬⊖θ↙↓ＥＥ⊕θΣＥη¬﹪ιλ⁺×│⊘ι×╵﹪ι²‖

Try it online! Link is to verbose version of code. Box-drawing characters have a 3 byte representation in Charcoal, so the above string is only 40 characters long. Explanation:
≔ＥηΠ…η⊕κη

Calculate the cumulative product of the intervals.
⪫┐┌×┬⊖θ↙

Print the first row of tick marks. The left and right characters are the wrong way around because the result is reflected later.
↓ＥＥ⊕θΣＥη¬﹪ιλ⁺×│⊘ι×╵﹪ι²

Calculate the number of intervals that are a factor of each tick mark. Generate a string of │s of half that length and add ╵ for odd lengths. Print each string downwards with subsequent strings in previous columns, i.e. reverse order.
‖

Reflect everything to get the ruler in left-to-right order.

Jelly,  42  41 bytes
‘Rm×\}Ṭ€+2/
⁽!ṣ;“½¥÷I‘ÄỌṙ-;⁶
Ḷ¬;.Ḥ~W;ñị¢Y

A full program.
Try it online!
Or see a test-suite
Note: this code has been altered from a full program -- ñ (next link as a dyad) has been replaced with 1ŀ (link at index 1 as a dyad) to allow it to be called multiple times by the footer.
How?
‘Rm×\}Ṭ€+2/ - Link 1, lower interval tick types: length; intervals  e.g. 7; [3,2]
‘           - increment length                                           8
 R          - range                                                      [1,2,3,4,5,6,7,8]
     }      - use right argument for this monad as if it were a dyad:
   ×\       -   cumulative reduce by multiplication                      [3,6]
  m         - modulo slice (vectorises)                                  [[1,4,7],[1,7]]
      Ṭ€    - untruth €ach                               [[1,0,0,1,0,0,1],[1,0,0,0,0,0,1]]
        +2/ - pairwise reduce with addition                              [[2,0,0,1,0,0,2]]
            -   -- yielding a list of types for each row of characters below the first
            -      where 0 is a space, 1 is a short tick-mark and 2 is a long tick-mark

⁽!ṣ;“½¥÷I‘ÄỌṙ-;⁶ - Link 2, make character set: no arguments
⁽!ṣ              - literal 9474
    “½¥÷I‘       - list of code-page indices   = [10,4,28,73]
   ;             - concatenate              [9474,10,4,28,73]
          Ä      - cumulative addition      [9474,9484,9488,9516,9589]
           Ọ     - to characters            "│┌┐┬╵"
            ṙ-   - rotate left by -1        "╵│┌┐┬"
               ⁶ - literal space character  ' '
              ;  - concatenate              "╵│┌┐┬ "

Ḷ¬;.Ḥ~W;ñị¢Y - Main link: length, L; intervals, I
Ḷ            - lowered range         [ 0, 1, 2, ..., L-1]
 ¬           - logical Not           [ 1, 0, 0, ..., 0]
   .         - literal 0.5
  ;          - concatenate           [ 1, 0, 0, ..., 0, 0.5]
    Ḥ        - double                [ 2, 0, 0, ..., 0, 1]
     ~       - bitwise NOT           [-3,-1,-1, ...,-1,-2]
      W      - wrap that in a list  [[-3,-1,-1, ...,-1,-2]]
        ñ    - call next Link (1) as a dyad (f(L, I))
       ;     - (left) concatenated with (right)
          ¢  - call last Link (2) as a nilad (f())
         ị   - (left) index into (right)  (1-indexed and modular)
           Y - join with newline characters
             - implicit print

Canvas, 42 41 40 bytes
┐”┬”┌”Ｏ⁸╷×ｏｏ╵（０）⁷｛＊Ｊ╵；∔｝ｍ｛２ｎ“╵”×；“│”××］⤢

Try it here! (with a font that monospaces the output)

Emacs Lisp, 303 bytes
(defun f(a)(princ'┌)(dotimes(i(1-(car a)))(princ'┬))(princ'┐)(let((m 1))(while(cadr a)(let((q(caadr a))(w (cadadr a)))(princ"\n")(dotimes(i(1+(car a)))(cond((if w(= 0(mod i(* m q w))))(princ'│))((= 0(mod i (* m q)))(princ'╵))(t(princ" "))))(setq m(* m q(if w w 1)))(setcdr a`(,(cddadr a)))))))

Use this function as (f '(30 (5 2))).
Better readable version:
(defun f (a)
  (princ '┌)
  (dotimes (i (1- (car a)))
    (princ '┬))
  (princ '┐)
  (let ((m 1))
    (while (cadr a)
      (let ((q (caadr a)) (w (cadadr a)))
    (princ "\n")
    (dotimes (i (1+ (car a)))
      (cond ((if w (= 0 (mod i (* m q w))))
        (princ '│))
       ((= 0 (mod i (* m q)))
        (princ '╵))
       (t
        (princ " "))))
    (setq m (* m q (if w w 1)))
    (setcdr a `(,(cddadr a)))))))

Ruby, 126 bytes
->l,i{y=1;[?┌+?┬*~-l+?┐]+i.each_slice(2).map{|j,k|x=y*j;y=k&&x*k;(0..l).map{|z|'│╵ '[(z%x<=>0)+(k ?z%y<=>0:1)]}*''}}

Try it online!
Looks rather verbose with all that each_slice stuff, but will do for now, unless I manage to find a golfier approach.
Takes input as l for length and i for intervals, returns an array of strings.

R, 175 170 bytes
function(l,i,`&`=rep)rbind(c('┌','┬'&l-1,'┐'),if(i)sapply(rowSums(!outer(0:l,cumprod(i),`%%`)),function(j,x=j%/%2,y=j%%2)c('│'&x,'╵'&y,' '&(1+sum(1|i))/2-x-y)))

Try it online!
Takes empty intervals as 0, returns a matrix of characters. TIO link displays the output pretty-printed.

Haskell, 167 164 149 bytes
n%l=unlines$("┌"++([2..n]>>"┬")++"┐"):[do p<-[0..n];let(j#a)b|1>p`rem`product(take j l)=a|1>0=b in(i-1)#(i#"│"$"╵")$" "|i<-[1,3..length l]]

Try it online! Slightly golfed different approach by Οurous.

n%l|let c=take(n+1).cycle;m&(x:y:r)=c('│':init([1..y]>>(m*x)!" "++"╵"))++'\n':(m*x*y)&r;m&[x]=c$'╵':(m*x)!" ";m&e=[]='┌':n!"┬"++"┐\n"++1&l
n!s=[2..n]>>s

Try it online! There are still some redundancies which look like they could be exploited, but so far they withstood all further golfing attempts.

The previous 167 byte solution is the same apart from newline handling and is probably slightly better readable:
n%l=unlines$('┌':n!"┬"++"┐"):(take(n+1)<$>1&l)
n!s=[2..n]>>s
m&(x:y:r)=cycle('│':init([1..y]>>(m*x)!" "++"╵")):(m*x*y)&r
m&[x]=[cycle$'╵':(m*x)!" "]
m&e=[]

Try it online!

Different approach at 158 bytes (Try it online!), can probably be shortened quite a bit more since I don't speak Haskell well.

PowerShell, 152 bytes
param($t,$i)"┌$('┬'*--$t)┐"
$i|%{$s=++$s*$_-1;$p=".(.{$s}|.*$)"
if($r){$r-replace$p,'│$1';rv r}else{$r=' '*($t+2)-replace$p,'╵$1'}}
if($r){$r}

Try it online!
Unrolled:
param($ticks,$intervals)
"┌$('┬'*--$ticks)┐"                         # implicit output
$intervals|%{
    $step=++$step*$_-1
    $pattern=".(.{$step}|.*$)"
    if($row){
        $row-replace$pattern,'│$1'          # implicit output
        Remove-Variable row
    }else{
        $row=' '*($ticks+2)-replace$pattern,'╵$1'
    }
}
if($row){$row}                              # implicit output

hmm... the fails with the right output

You are right. 1) I didn't see a rule that allows trailing new line at the end. 2) and I don't like that the code sometimes adds a new line at the end, and sometimes it doesn't. :)

C# (Visual C# Interactive Compiler), 204 bytes
a=>b=>{Write("┌"+"┐\n".PadLeft(++a,'┬'));for(int i=1;;i++,WriteLine())for(int j=0;j<a;){var m=b.Select((c,d)=>b.Take(d+1).Aggregate((e,f)=>e*f)).Count(c=>j++%c<1);Write(m<1|i>m?" ":m<2?"╵":"|");}}

Try it online!
Outputs, but gets stuck in an infinite loop.

Clean, 221 201 195 162 bytes
import StdEnv
$n l=[["┌":repeatn(n-1)"┬"]++["┐"]:[[if(?(i-1))if(?i&&l%(i,i)>[])"│""╵"" "\\p<-[0..n],let?j=1>p rem(prod(l%(0,j)))
]\\i<-[1,3..length l]]]

Try it online!
Returns a list of lists of UTF-8 characters (as strings, since Clean has no innate UTF-8 support).
Works by generating the first line, then taking the product of prefixes of the list provided in groups of two, and checks which mark to draw based on whether the product divides the current character position.
Ungolfed:
$ n l
    = [
        ["┌": repeatn (n - 1) "┬"] ++ ["┐"]:
        [
            [
                if(? (i - 1))
                    if(? i && l%(i, i) > [])
                        "│"
                        "╵"
                    " "
                \\ p <- [0..n]
                , let
                    ? j = 1 > p rem (prod (l%(0, j)))
            ]
            \\ i <- [1, 3.. length l]
        ]
    ]

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Finding Gaps in Date Ranges
Given a list of date ranges r as input, output or return any ranges not found in r.
For the sake of this example, input will be in YYYY-MM-DD format.
Let's say you have three date ranges:
[2019-01-01, 2019-02-01]
[2019-02-02, 2019-04-05]
[2019-06-01, 2019-07-01]

You can see that there is a gap in between 2019-04-05 and 2019-06-01.
The output will be that gap: [2019-04-06, 2019-05-31]
Rules

Input and output can be in any reasonable date or collection format, as long as it is consistent.
Assume the input is not ordered.
Your date range does not have to be [latest, earliest], but it does have to follow rule 2.
Assume there are no overlapping dates in the input

Test Cases:
Input: [[2019-01-01, 2019-02-01],[2019-02-02, 2019-04-05],[2019-06-01, 2019-07-01]]
Output: [[2019-04-06, 2019-05-31]]

Input: [[2019-01-01, 2019-02-01],[2018-02-02, 2018-04-05],[2019-06-01, 2019-07-01]]
Output: [[2018-04-06, 2018-12-31], [2019-02-02, 2019-05-31]]

Input: [[2019-01-01, 2019-02-01],[2019-02-02, 2019-03-02],[2019-03-03, 2019-07-01]]
Output: []

Input: [[2019-01-01, 2019-02-01], [2019-11-02, 2019-11-20]]
Output: [[2019-02-02, 2019-11-01]]

Input: [[2019-01-01, 2019-02-01],[2019-02-03, 2019-04-05]]
Output: [[2019-02-02, 2019-02-02]] or [[2019-02-02]]

I suggest reworking all the example dates to ISO format, YYYY-MM-DD as the current format is both foreign to many people, and made even harder to parse due to using small days-of-month≤12.

@Adám Good idea, updated.

May we take input as .NET OLE Automation Dates?

@Adám Yes. Any reasonable date format is acceptable.

Will the dates be ordered? Also, within a pair of dates, will the later one be last?

@EmbodimentofIgnorance The pair of dates do not have to be sequential, but assume the ranges in your input will not be ordered from latest to earliest. The output does not have to ordered; If it isn't, please specify so in your post.

seems there's a typo in last test case last input too many brackets?

@NahuelFouilleul Thanks for catching that. Updated.

what about BC vs AD?

@donbright You don't have to handle BC years if that's not native in your language.

Do adjacent date ranges have to be combined in the output? e.g. is [[2019-02-02, 2019-7-01],[2019-07-02, 2019-11-01]] a valid output for the last test case? Can they overlap?

@JoKing To answer your second question: I'm going to say no unless a strong case is made otherwise. I am curious, why would your solution return two ranges?

I was trying to see if I could return a series of one day ranges as output

I suggest adding a test case which yields a range of a single date if that should be handled. (e.g. [[2019-01-01, 2019-02-01],[2019-02-03, 2019-04-05]] -> [2019-02-02, 2019-02-02]) In such a case can answers have the single date as the range or must there be two? (i.e. is [2019-02-02] acceptable or not there?)

@JonathanAllan Added to the test cases. Thanks for the suggestion.

Another example to show why Python range(1, n) exclude n. (Things would be much easier if all ranges exclude the last in this case.)

SQL should be pretty convenient for this. Can we take input from a database table?

@Titus Yes, that's fine.

APL (Dyalog Extended), 28 25 24 bytes
Anonymous tacit prefix function. Argument and result are 2-column matrices of day numbers since an epoch, each row representing a range.
1 ¯1+⍤1∘{⍵⌿⍨1<-⍨/⍵}1⌽⍢,∧

Try it online! The In pre-processor function converts from a list of pairs of 3-element lists (dates in ISO order) to a 2-column matrix of IDNs, International Day Numbers (days since 1899-12-31). The Out post-processor function converts from a matrix of IDNs to a matrix of 3-element lists.
∧ sort rows ascending
1⌽ cyclically rotate the dates one step left
 ⍢, while ravelled (flattened) — afterwards, reshape back to original shape
1 ¯1+ add one and negative one
⍤1 using that list for each row
∘ of the result of
{…} the following lambda:
 ⍵ the argument
 -⍨/ subtract left-hand date from right-hand date, row-wise
 1< mask where differences exceed one (i.e. where ranges are not adjacent)
 ⍵⌿⍨ filter the rows by that mask

C# (Visual C# Interactive Compiler), 108 bytes
n=>{n.Sort();for(int i=0;;)Write(n[i].b.AddDays(1)==n[++i].a?"":n[i-1].b.AddDays(1)+""+n[i].a.AddDays(-1));}

Outputs by printing in the format DD/MM/YYYY 12:00:00 AMDD/MM/YYYY 12:00:00 AM. Will cause an IndexOutOfRange exception, which is fine per meta consensus.
Try it online!
If we take input in the form of days since the unix epoch, we can get this down to...
83 bytes
n=>{n.Sort();for(int i=0;;)Print(n[i].b+1==n[++i].a?"":n[i-1].b+1+" "+(n[i].a-1));}

Try it online!
We can golf this down even further with the /u:System.Array flag, for...
78 bytes
n=>{Sort(n);for(int i=0;;)Print(++n[i].b==n[++i].a--?"":n[i-1].b+" "+n[i].a);}

Try it online!

Perl 6, 46 bytes
{@_.sort[1..*-2].map:{$^a+1,$^b-1 if $b>$a+1}}

Try it online!
Takes a list of Date pairs.

Any idea why this possible golf mangles the date output?

@JoKing I noticed that, too, and filed a bug.

PHP, 208 197 190 177 bytes
hunky chunky sat on a wall ... though the new approach had quite some golfing potential.
function($a){sort($a);for($m=$x=$a[0][0];$f=$m<=$x;$f^$g&&print($g=$f)?"$m/":"$n
",$m=date("Y-m-d",strtotime($n=$m)+9e4))foreach($a as$d)$x=max($x,$d[1|$f&=$m<$d[0]|$m>$d[1]]);}

function takes array of ranges [start,end] in ISO format, prints gap intervals. Try it online.

breakdown
function($a){
    sort($a);                           # sort ranges (for easy access to min date)
    for($m=$x=$a[0][0];$f=$m<=$x;       # loop from min date to max date, 1. set flag
        $f^$g&&print($g=$f)?"$m/":"$n\n",       # 4. flag changed: backup flag, print date
        $m=date("Y-m-d",strtotime($n=$m)+9e4)   # 5. backup and increment date
    )foreach($a as$d)
        $x=max($x,$d[1                          # 2. find max date
            |$f&=$m<$d[0]|$m>$d[1]              # 3. date found in ranges: clear flag
        ]);
}

Perl 5, 130 bytes
/-(\d+)-/,$_=strftime"%Y-%m-%d",0,0,0,$'+($|--||-1),$1-1,$`-1900 for@F=sort@F;$,lt$;&&say"$, $;"while($,,$;)=@F[++$i,$i+1],++$i<@F

TIO

Bash, 125 bytes
set `sort<<<$1`;shift;for a;{ s=$[x++%2?-1:1]day;c=`date -d$a\ $s +%Y-%m-%d`;[ $p ]&&{ [[ $p < $c ]]&&echo $p $c;p=;}||p=$c;}

TIO

Jelly, 13 bytes
FṢṖḊs2+Ø+>/Ðḟ

Jelly (currently) has no built-in dates, so this uses days-since-epoch.
The input list of ranges (pairs of integers) may be in mixed order and mixed directions.
The result is a list of ascending ranges in ascending order.
Try it online! (footer formats in order to show an empty list as [])
How?
Note: This relies on the assurance that "there are no overlapping dates in the input" as stated in the rules.
FṢṖḊs2+Ø+>/Ðḟ - Link: list of pairs of integers
F             - flatten
 Ṣ            - sort
  Ṗ           - pop (remove tail)
   Ḋ          - dequeue (remove head)
    s2        - split into twos
       Ø+     - literal [1,-1]
      +       - add (vectorises)
           Ðḟ - filter discard those for which:
          /   -   reduce by:
         >    -     greater than?

Interesting, I didn't know that Jelly didn't have date support. Is this the usual approach? Use days since epoch?

Days since epoch is, I believe, used by some systems (Excel maybe). Seconds since epoch is more common (e.g Unix). I just went with something which seems to cover the requirements, albeit fairly laxly.

Boo, you could calculate the dates manually. ;P Days since epoch is indeed used more often for languages that doesn't support dates. I do feel like it makes this challenge A LOT easier, though.

@KevinCruijssen heh, agreed.

R, 88 bytes
function(a,b=a[order(a$x),],d=c(b$x[-1]-b$y[-nrow(b)],0))data.frame(b$y+1,b$y+d-1)[d>1,]

Try it online!
This takes a data frame of date ranges as input and outputs a data frame with the ranges that are missing. I’m fairly sure this could be golfed more, but I ran into issues with c, cbind and others stripping the date class.

C# (Visual C# Interactive Compiler), 103 bytes
x=>{var(a,_)=x[0];foreach(var(b,c)in x.OrderBy(y=>y)){if(a<b)Print((a,b.AddDays(-1)));a=c.AddDays(1);}}

Try it online!
Input is a list of start/end date tuples. Outputs each missing range to STDOUT.
// x: input list of start/end date tuples
x=>{
  // variable definitions...
  // a: 1 day after the end date of the previous range
  // b: start of the current range
  // c: end of the current range

  // start by deconstructing the start date of the first tuple
  // into a. a will then be a DateTime and will contain a value
  // at least a large as the smallest start date.
  var(a,_)=x[0];
  // iterate over sorted ranges
  foreach(var(b,c)in x.OrderBy(y=>y)){
    // if the day after the end of the previous range is less
    // than the start of the current range, then print the
    // missing days.
    if(a<b)
      Print((a,b.AddDays(-1)));
    // save the day after the current range to a for next iteration
    a=c.AddDays(1);
  }
}

128

Hah - if you do print like Embodiment of Ignorance you can get really small - Try it online!

Nice. Also wtf their input method for the latter two

Well actually... that looks really incorrect

Hah - I got a little carried away deleting :) how about this? 103

Yeah that looks fine now

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
2-Dimensional Bubble Sort
Sorting makes no sense for a 2-dimensional array... or does it?
Your task is to take an input grid and apply a bubble-sort-like algorithm to it until all values in the grid are non-decreasing from left to right and top to bottom along every row and column.
The algorithm works as follows:

Each pass goes row by row, top to bottom, comparing/swapping each cell with its right and below neighbors.

if the cell is greater than only one of its right and below neighbors, swap with the one that it is greater than
if the cell is greater than both its right and below neighbors, swap with the smaller neighbor
if the cell is greater than both its right and below neighbors, which are the same value, then swap with the below neighbor.
if the cell is not greater than either of its right and below neighbors, do nothing

Continue this until no swaps are made throughout the entire pass. This will be when every row and column are in order, left to right and top to bottom.

Example
4 2 1
3 3 5
7 2 1

The first row of the pass will swap the 4 and the 2, then the 4 with the 1.
2 1 4
3 3 5
7 2 1

When we get the the middle 3, it will be swapped with the 2 below
2 1 4
3 2 5
7 3 1

Then the 5 gets swapped with the 1 below
2 1 4
3 2 1
7 3 5

The last row of the first pass moves the 7 all the way to the right
2 1 4
3 2 1
3 5 7

Then we go back to the top row again
1 2 1
3 2 4
3 5 7

And continue row by row...
1 2 1
2 3 4
3 5 7

... until the grid is "sorted"
1 1 2
2 3 4
3 5 7

Another Example
3 1 1
1 1 1
1 8 9

becomes
1 1 1
1 1 1
3 8 9

rather than
1 1 1
1 1 3
1 8 9

because the downward swap takes priority when both the right and below neighbors of a cell are equal.
A step-by-step reference implementation can be found here.
Test cases
5 3 2 6 7 3 1 0
3 2 1 9 9 8 3 0
3 2 2 8 9 8 7 6

becomes
0 0 1 1 2 2 3 6
2 2 3 3 6 7 8 8
3 3 5 7 8 9 9 9

2 1 2 7 8 2 1 0
2 2 2 2 3 2 1 0
1 2 3 4 5 4 3 2
9 8 7 6 5 4 3 6
6 5 4 3 2 2 1 0

becomes
0 0 0 1 1 1 2 2
1 1 2 2 2 2 2 2
2 2 2 2 3 3 3 3
3 4 4 4 4 5 6 6
5 5 6 7 7 8 8 9

Rules

You can take the input grid in any convenient format
You may assume the grid values are all non-negative integers in the unsigned 16-bit range (0-65535).
You may assume the grid is a perfect rectangle and not a jagged array. The grid will be at least 2x2.
If you use another algorithm of sorting, you must supply a proof that it will always produce the same resulting order as this particular brand of 2D bubble sorting, no matter what the input is. I expect this to be a non-trivial proof, so you're probably better off using the described algorithm.

Happy Golfing!

Do we have to implement the exact algorithm specified in your challenge?

Will the array be at least 2x2?

@EmbodimentofIgnorance: only if you prove that it results in an equivalent sort in all cases. I expect this to be a non-trivial proof.

Whoever voted to close this as "too broad", would you mind explaining your reasoning? This was in the sandbox for a week with 3 upvotes and no comments for correction, so the prior consensus was that this was a decent challenge.

JavaScript (Node.js), 129 bytes
a=>[...a+''].map(t=>a.map((l,y)=>l.map((v,x)=>(L=a[y+1]||[],d=L[X=x],r=l[x+1],v>r?r>=d||(L=l,X++):v>d||(L=l),l[x]=L[X],L[X]=v))))

Try it online!

APL (Dyalog Unicode), 75 bytesSBCS
Thanks to @Adám for saving 11 bytes.
{m⊣{d r←⍵∘(s⌊+)¨↓∘.=⍨⍳2⋄∨/c>a c b←m[r⍵d]:m⊢←⌽@⍵(d r⊃⍨1+b>a)⊢m⋄⍬}¨⍳s←⍴m←⍵}⍣≡

Try it online!

-11

R, 169 165 144 132 bytes
function(m,n=t(m)){while(any(F-(F=n)))for(i in 1:sum(1|n)){j=(j=i+c(0,r<-nrow(n),!!i%%r))[order(n[j])[1]];n[c(i,j)]=n[c(j,i)]};t(n)}

Try it online!

Wolfram Language (Mathematica), 183 bytes
(R=#;{a,b}=Dimensions@R;e=1;g:=If[Subtract@@#>0,e++;Reverse@#,#]&;While[e>0,e=0;Do[If[j<b,c=R[[i,j;;j+1]];R[[i,j;;j+1]]=g@c]If[i<a,c=R[[i;;i+1,j]];R[[i;;i+1,j]]=g@c],{i,a},{j,b}]];R)&

Try it online!
I'm not a Mathematica expert, I'm sure it can be done shorter. Particularly I think that the double if statement could be shortened using Transpose but I don't know how.

Charcoal, 118 bytes
≔Ｉ9.e999η≧⁻ηηＦθ⊞ιη⊞θ⟦η⟧ＦΣＥθＬι«ＦＬθ«≔§θκιＦＬι«≔§ιλζ≔§ι⊕λε≔§§θ⊕κλδ¿››ζδ›δε«§≔§θ⊕κλζ§≔ιλδ»¿›ζε«§≔ι⊕λζ§≔ιλε»»»»¿⊟θ¿Ｅθ⊟ιＥθ⪫ι

Try it online! Link is to verbose version of code. I've also spent a few bytes on some prettier formatting. Explanation:
≔Ｉ9.e999η≧⁻ηηＦθ⊞ιη⊞θ⟦η⟧

JavaScript has the convenient property that a[i]>a[i+1] is false if i is the last element of the array. To emulate that in Charcoal, I calculate a nan by casting 9.e999 to float and then subtracting it from itself. (Charcoal doesn't support exponential float constants.) I then pad the original array on the right with the nan and also add an additional row containing just the nan. (Charcoal's cyclic indexing means that I only need one element in that row.)
ＦΣＥθＬι«

Loop for each element in the array. This should be more than enough loops to get the job done, as I'm including all the extra nans too.
ＦＬθ«≔§θκι

Loop over each row index and get the row at that index. (Charcoal can do both with an expression but not with a command.) This includes the dummy row but that's not a problem because all of the comparisons will fail.
ＦＬι«≔§ιλζ

Loop over each column index and get the value at that index. Again, this will loop over the dummy values but the comparisons will just fail again.
≔§ι⊕λε≔§§θ⊕κλδ

Also get the values to the right and below.
¿››ζδ›δε«§≔§θ⊕κλζ§≔ιλδ»

If the cell is greater than the value below and it's not true that the value below is greater than the value to the right then swap the cell with the value below.
¿›ζε«§≔ι⊕λζ§≔ιλε»»»»

Otherwise if the cell is greater than the value to the right then swap them.
¿⊟θ¿Ｅθ⊟ιＥθ⪫ι

Remove the nan values and format the array for implicit output.

Python 2, 215 208 bytes
m=input()
h=len(m);w=len(m[0])
while 1:
 M=eval(`m`)
 for k in range(h*w):i,j=k/w,k%w;v,b,a=min([(M[x][y],y,x)for x,y in(i,j),(i+(i<h-1),j),(i,j+(j<w-1))]);M[i][j],M[a][b]=M[a][b],M[i][j]
 M!=m or exit(M);m=M

Try it online!
-7 bytes, thanks to ovs

208 bytes with output to Debug / STDERR.

C# (.NET Core), 310 bytes
Without LINQ.  Uses using System.Collections.Generic only for formatting the output after the function is returned.  Thing is stupid huge.  Looking forward to the golfs!
a=>{int x=a.GetLength(0),y=a.GetLength(1);bool u,o;int j=0,k,l,t,z;for(;j<x*y;j++)for(k=0;k<x;k++)for(l=0;l<y;){o=l>y-2?0>1:a[k,l+1]<a[k,l];u=k>x-2?0>1:a[k+1,l]<a[k,l];z=t=a[k,l];if((u&!o)|((u&o)&&(a[k,l+1]>=a[k+1,l]))){t=a[k+1,l];a[k+1,l]=z;}else if((!u&o)|(u&o)){t=a[k,l+1];a[k,l+1]=z;}a[k,l++]=t;}return a;}

Try it online!

Python 2, 198 bytes
G=input()
O=e=enumerate
while O!=G:
 O=eval(`G`)
 for i,k in e(G):
	for j,l in e(k):v,x,y=min((G[i+x/2][j+x%2],x&1,x/2)for x in(0,1,2)if i+x/2<len(G)and j+x%2<len(k));G[i][j],G[i+y][j+x]=v,l
print G

Try it online!
Developed independently from TFeld's answer, has some differences.

Clean, 240 bytes
import StdEnv
$l=limit(iterate?l)
?[]=[]
?l#[a:b]= @l
=[a: ?b]
@[[a,b:c]:t]#(t,[u:v])=case t of[[p:q]:t]=([q:t],if(a>p&&b>=p)[b,p,a]if(a>b)[a,b,p][b,a,p]);_=(t,sortBy(>)[a,b])
=[v%(i,i)++j\\i<-[0..]&j<- @[[u:c]:t]]
@l=sort(take 2l)++drop 2l

Try it online!
Implements the algorithm exactly as described.
Link includes input parsing to take the format in the question.

Kotlin, 325 bytes
{m:Array<Array<Int>>->val v={r:Int,c:Int->if(r<m.size&&c<m[r].size)m[r][c]
else 65536}
do{var s=0>1
for(r in m.indices)for(c in m[r].indices)when{v(r,c)>v(r+1,c)&&v(r+1,c)<=v(r,c+1)->m[r][c]=m[r+1][c].also{m[r+1][c]=m[r][c]
s=0<1}
v(r,c)>v(r,c+1)&&v(r,c+1)<v(r+1,c)->m[r][c]=m[r][c+1].also{m[r][c+1]=m[r][c]
s=0<1}}}while(s)}

Try it online!