It looks like you came from one of my previous answer in 2016: mgcv: How to set number and / or locations of knots for splines, borrowing my code snippet:
my_knots <- myfit$smooth[[1]]$xp
plot(x, y, col= "grey", main = "my knots");
lines(x, myfit$linear.predictors, col = 2, lwd = 2)
abline(v = my_knots, lty = 2)
In that answer, my demonstration was made with cubic regression spline (bs = 'cr'), where knot placement is simple to do. But for B-splines, things are more complicated. So take this answer as a complement to that answer.
For B-spline classes in mgcv, i.e., 'bs' being "bs" (?b.spline), "ps" (?p.spline) or "ad" (?adaptive.smooth), the argument k is the number of B-splines, not the number of knots. And the first take-home message is: the number of B-splines is NOT equal to the number of knots.
Knot placement for B-splines is a dirty work. Usually you only specify k and mgcv will place knots automatically for you (see for example, Extract knots, basis, coefficients and predictions for P-splines in adaptive smooth). If you want to control knot placement yourself, the number of knots you provide must be compatible with k. This can cause great confusion if you don't well understand B-splines.
I highly recommend your reading the Appendix (page 33-34) of one of my work: General P-splines for Non-uniform B-splines, to know some fundamental stuff of B-splines. Make sure you understand what are the domain, interior knots and auxiliary boundary knots. In the following, I will just show you how to use these knowledge to write the correct code.
Here is how to place knots for your example.
## degree of spline
deg <- 3
## domain
a <- min(x)
#[1] 5.86
b <- max(x)
#[1] 24.16
## interior knots (must be between a and b)
xs <- c(6, 20)
#[1]  6 20
## domain knots
xd <- c(a, xs, b)
#[1]  5.86  6.00 20.00 24.16
## clamped auxiliary boundary knots
left.aux <- rep(a, deg)
#[1] 5.86 5.86 5.86
right.aux <- rep(b, deg)
#[1] 24.16 24.16 24.16
## complete B-spline knots
my.knots <- c(left.aux, xd, right.aux)
#[1]  5.86  5.86  5.86  5.86  6.00 20.00 24.16 24.16 24.16 24.16
Here is how to specify k for your example.
my.k <- length(xs) + deg + 1
#[1] 6
Now we can work with mgcv.
myfit <- gam(y ~ s(x, bs = 'bs', k = my.k),
             knots = list(x = my.knots))
#Family: gaussian 
#Link function: identity
#
#Formula:
#y ~ s(x, bs = "bs", k = my.k, m = deg)
#
#Estimated degrees of freedom:
#3.81  total = 4.81
The knots you passed in are stored here (which agree with my.knots):
## For B-spline classes, knots are stored in $knots instead of $xp
myfit$smooth[[1]]$knots
#[1]  5.86  5.86  5.86  5.86  6.00 20.00 24.16 24.16 24.16 24.16
Accompanying General P-splines for Non-uniform B-splines are R packages gps and gps.mgcv. The latter package introduces a new "gps" class to mgcv, where bs = 'ps' and bs = 'bs' are special cases of bs = 'gps'. The new "gps" class makes knot placement easier, because it automatically places auxiliary boundary knots for you and you only need to provide interior knots.
## The package stays on GitHub for the moment
## but will be on CRAN in the future.
## You may need to first install package 'devtools' from CRAN.
devtools::install_github("ZheyuanLi/gps")
devtools::install_github("ZheyuanLi/gps.mgcv")
library(gps.mgcv)
## as same as using 'bs = 'bs''
myfit <- gam(y ~ s(x, bs = 'gps', k = my.k, xt = list(derivative = TRUE)),
             knots = list(x = xs))  ## provide interior knots
## the novel general P-spline
gpsfit <- gam(y ~ s(x, bs = 'gps', k = my.k),
             knots = list(x = xs))  ## provide interior knots
Construction information (domain, interior knots, etc) are stored in myfit$smooth[[1]]$xt and gpsfit$smooth[[1]]$xt.