Zsh + coreutils, 406 375 bytes
g()ls -t<>"She$d the $1 to catch the $2,"
set bird spider \ swallow iggled\
<<Z
${b=There was an old lady who${d=$3ed} a }fly.${5=
I don't know why she$d that fly,
Perhaps she'll die.
$b}$2,
That wr$4and $4and j$4inside her.
`g $2 fly`$5$1,
How absurd${6= to$3 a }$1.
`g $@`$5cat,
Imagine that$6cat.
`g cat $1`$5dog,
What a hog$6dog.
`g dog cat`$5horse,
She died of course.
Tricks:
- the
g
function creates the line as a file and thenls
lists the files in the current directory in order of creation (-t
), to avoid having to repeat the previous lines every time.- I used
<>
(which creates the file before the command is executed) instead of>...;
because using multiple commands in a function requires{}
around them
- I used
set bird ...
assigns the words to$1
,$2
, etc.\ swallow
includes a space at the start of without needing to use quotes<<Z
starts a heredoc which is effectively a long interpolated string${b=There...}
is a shorthand form settingb
to that string and substituting its value in- Indexed variables like
$1
,$2
, etc. can be substituted without a space afterwards (rather than being interpreted as a variable called5dog
, for example), so we prefer them as it allows us to include the space inside the assignment to avoid repeating it g $@
: since we set$1
and$2
tobird
andspider
respectively, we can pass all the numbered variables tog
in one go with$@
instead ofg $1 $2
(it ignores the extra ones,$3
etc.)