[Question]
  [
### Introduction:
I think we all know it, and it has probably been translated in loads of different languages: the "Head, Shoulders, Knees and Toes" children song:
> 
> Head, shoulders, knees and toes, knees and toes  
> 
>  Head, shoulders, knees and toes, knees and toes  
> 
>  And eyes and ears and mouth and nose  
> 
>  Head, shoulders, knees and toes, knees and toes  
> 
> [wikipedia](https://en.wikipedia.org/wiki/Head,_Shoulders,_Knees_and_Toes)
> 
> 
> 
---
### Challenge:
**Input:** A positive integer.
**Output:** Output one of the following words based on the input as n-th index:
```
head
shoulders
knees
toes
eyes
ears
mouth
nose
```
Here the body parts are appended with the indexes:
```
Head (0), shoulders (1), knees (2) and toes (3), knees (4) and toes  (5)
Head (6), shoulders (7), knees (8) and toes (9), knees (10) and toes (11) 
And eyes (12) and ears (13) and mouth (14) and nose (15)
Head (16), shoulders (17), knees (18) and toes (19), knees (20) and toes (21)
Head (22), shoulders (23), knees (24) and toes (25), knees (26) and toes  (27)
Head (28), shoulders (29), knees (30) and toes (31), knees (32) and toes (33) 
And eyes (34) and ears (35) and mouth (36) and nose (37)
Head (38), shoulders (39), knees (40) and toes (41), knees (42) and toes (43)
etc.
```
### Challenge rules:
* You are of course allowed to use 1-indexed input instead of 0-indexed. But please specify which one you've used in your answer.
* The output is case insensitive, so if you want to output it in caps that's fine.
* You should support input up to at least 1,000.
### General rules:
* This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), so shortest answer in bytes wins.  
Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
* [Standard rules apply](http://meta.codegolf.stackexchange.com/questions/2419/default-for-code-golf-program-function-or-snippet/2422#2422) for your answer, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters, full programs. Your call.
* [Default Loopholes](http://meta.codegolf.stackexchange.com/questions/1061/loopholes-that-are-forbidden-by-default) are forbidden.
* If possible, please add a link with a test for your code.
* Also, please add an explanation if necessary.
### Test cases (0-indexed):
```
Input:  Output:
0       head
1       shoulders
7       shoulders
13      ears
20      knees
35      ears
37      nose
98      knees
543     nose
1000    knees
```
  
[Answer]
## JavaScript (ES6), ~~91~~ ~~88~~ 87 bytes
```
n=>'knees,toes,head,shoulders,eyes,ears,mouth,nose'.split`,`[(245890>>(n%22&~1))&6|n%2]
```
### How it works
We have 4 distinct pairs of words that always appear together: 'head' is always followed by 'shoulders', 'knees' is always followed by 'toes', etc.
Therefore, we can use the following index:
```
00: [ 'knees', 'toes' ]
01: [ 'head', 'shoulders' ]
10: [ 'eyes', 'ears' ]
11: [ 'mouth', 'nose' ]
```
And compress the whole sequence (in reverse order) into the following binary mask:
```
00 00 01 11 10 00 00 01 00 00 01
```
We use `[ 'knees', 'toes' ]` as the first pair to get as many leading zeros as possible.
We pad this sequence with an extra `0` so that the extracted value is premultiplied by 2, which leads to:
```
0b00000111100000010000010 = 245890
```
Hence the final formula for the correct word:
```
(245890 >> (n % 22 & ~1)) & 6 | n % 2
```
### Test cases
```
let f =
n=>'knees,toes,head,shoulders,eyes,ears,mouth,nose'.split`,`[(245890>>(n%22&~1))&6|n%2]
console.log(f(0));    // head
console.log(f(1));    // shoulders
console.log(f(7));    // shoulders
console.log(f(13));   // ears
console.log(f(20));   // knees
console.log(f(35));   // ears
console.log(f(37));   // nose
console.log(f(98));   // knees
console.log(f(543));  // nose
console.log(f(1000)); // knees
```
[Answer]
# [05AB1E](http://github.com/Adriandmen/05AB1E), ~~36~~ ~~35~~ 34 bytes
```
“‡ä¾ØsÏ©s¸±s“#2ä¤«Ð“—íÖÇ©¢ÄÃ“#s)˜è
```
[Try it online!](http://05ab1e.tryitonline.net/#code=4oCc4oChw6TCvsOYc8OPwqlzwrjCsXPigJwjMsOkwqTCq8OQ4oCc4oCUw63DlsOHwqnCosOEw4PigJwjcynLnMOo&input=MTAwMA) or as a [Test suite](http://05ab1e.tryitonline.net/#code=fHbigJzigKHDpMK-w5hzw4_CqXPCuMKxc-KAnCMyw6TCpMKrw5DigJzigJTDrcOWw4fCqcKiw4TDg-KAnCNzKcucecOoLA&input=MAoxCjcKMTMKMjAKMzUKMzcKOTgKNTQzCjEwMDA)
**Explanation**
```
“‡ä¾ØsÏ©s¸±s“                        # dictionary string 'head shoulders knees toes'
             #                       # split on spaces
              2ä                     # split in 2 parts
                ¤                    # get the last part ['knees', 'toes']
                 «                   # concatenate and flatten
                                     # STACK: [['head', 'shoulders'], ['knees', 'toes'], 'knees', 'toes']
                  Ð                  # triplicate
                   “—íÖÇ©¢ÄÃ“        # dictionary string 'eyes ears mouth nose'
                             #s      # split on spaces and swap top 2 elements of stack
                               )˜    # wrap stack in a list and flatten
                                 è   # index into list with input
```
In short, we build the list
`['head', 'shoulders', 'knees', 'toes', 'knees', 'toes', 'head', 'shoulders', 'knees', 'toes', 'knees', 'toes', 'eyes', 'ears', 'mouth', 'nose', 'head', 'shoulders', 'knees', 'toes', 'knees', 'toes']` and index into it with input (0-indexed).
[Answer]
# Python 2, ~~158~~ ~~148~~ ~~137~~ ~~128~~ ~~114~~ ~~109~~ 104 bytes
Lookup table seems better. Also shortened the big string and reordered the items. -5 bytes thanks to Rod for using string as a list.
```
c=int('602323'*2+'4517602323'[input()%22])
print"smkteehnhonoyaeooueeerasutesssdelhs"[c::8]+"ders"*(c<1)
```
initial solution:
```
n=input()%22
n-=10*(n>15)
if n>=12:n-=8
else:n%=6;n-=2*(n>3)
print"hskteemnehnoyaooaoeeerusduessste ls   h  d       e       r       s"[n::8].strip()
```
[Answer]
## Perl, 74 bytes
**73 bytes code + 1 for `-p`.**
```
$_=(@a=(head,shoulders,(knees,toes)x2),@a,eyes,ears,mouth,nose,@a)[$_%22]
```
Uses 0-based indexing. Doesn't output a separator, but that could be amended with `-l` in the flags.
[Try it online](https://ideone.com/aiZv70).
[Answer]
# Python 2, ~~97~~ 90 Bytes
There may be some math that makes it so I don't have to make the word list, but this works for now!
```
lambda n,k='head shoulders '+'knees toes '*2:(k*2+'eyes ears mouth nose '+k).split()[n%22]
```
*Thanks to Flp.Tkc for saving 7 bytes :)*
[Answer]
# Java 7, ~~155~~ ~~137~~ ~~131~~ ~~123~~ ~~111~~ 110 bytes
```
String c(int i){return"knees,toes,head,shoulders,eyes,ears,mouth,nose".split(",")[(245890>>(i%22&~1))&6|i%2];}
```
-12 bytes thanks to *@Neil*.  
-1 byte by shamelessly creating a port of [*@Arnauld*'s amazing answer](https://codegolf.stackexchange.com/a/100157/52210).
Java is 0-indexed, so that's what I've used.
**Ungolfed & test code:**
[Try it here.](https://ideone.com/aVqcoX)
```
class M{
  static String c(int i){
    return "knees,toes,head,shoulders,eyes,ears,mouth,nose".split(",")
      [(245890>>(i%22&~1))&6|i%2];
  }
  public static void main(String[] a){
    System.out.println(c(0));
    System.out.println(c(1));
    System.out.println(c(7));
    System.out.println(c(13));
    System.out.println(c(20));
    System.out.println(c(35));
    System.out.println(c(37));
    System.out.println(c(98));
    System.out.println(c(543));
    System.out.println(c(1000));
  }
}
```
**Output:**
```
head
shoulders
shoulders
ears
knees
nose
ears
knees
nose
knees
```
[Answer]
# C, ~~153 bytes~~ 141 bytes
```
*b[]={"head","shoulders","knees","toes","eyes","ears","mouth","nose"};i;char*g(a){a%=22;i=(a+4)%10;return b[a<4?a:(a&12)>8?a-8:i<2?i:a%2+2];}
```
Thanks to @cleblanc for 4 bytes. Declaring b globally throws a ton of warnings about casting to int, but didn't break for me.
Ungolfed:
```
*b[]={"head","shoulders","knees","toes","eyes","ears","mouth","nose"};
i;
char* g(a) {
    a%=22;
    i=(a+4)%10;
    return b[a < 4        ? a
            :(a & 12) > 8 ? a-8
            :i < 2        ? i
            :               a % 2 + 2];
}
```
It's not the smallest answer, but I liked the technique, and had fun finding a few patterns.
Changelog:
* Moved `b` to global to avoid `char` (4 bytes)
* `a > 11 && a < 16` => `(a & 12) > 8` (2 bytes)
* `i=(a-6)%10` => `i=(a+4)%10` so that `i < 2 && i >= 0` => `i < 2` (6 bytes)
[Answer]
# JavaScript (ES6) ~~91~~ 89 Bytes
```
f=
n=>((d='head:shoulders:'+(b='knees:toes:')+b)+d+'eyes:ears:mouth:nose:'+d).split`:`[n%22]
console.log(f.toString().length)
console.log(f(0) === 'head')
console.log(f(1) === 'shoulders')
console.log(f(7) === 'shoulders')
console.log(f(13) === 'ears')
console.log(f(20) === 'knees')
console.log(f(35) === 'ears')
console.log(f(37) === 'nose')
console.log(f(98) === 'knees')
console.log(f(543) === 'nose')
console.log(f(1000) === 'knees')
```
[Answer]
## R, 95 bytes
```
c(o<-c("head","shoulders",y<-c("knees","toes"),y),o,"eyes","ears","mouth","nose",o)[scan()%%22]
```
Creates a character vector to function as a lookup table. Takes input from stdin (`1-indexed`) and `%%22` to find the corresponding body part.
Bonus: `%%` is vectorized which means that this will work with a vector inputs as well.
[Test cases on R-fiddle](http://www.r-fiddle.org/#/fiddle?id=t1r8Zkb3&version=1) (Note that this is a named function because `scan` doesn't work on R-fiddle)
[Answer]
# jq, 80 characters
(77 characters code + 3 characters command line option)
```
((("head shoulders "+"knees toes "*2)*2+"eyes ears mouth nose ")*2/" ")[.%22]
```
Sample run:
```
bash-4.3$ jq -r '((("head shoulders "+"knees toes "*2)*2+"eyes ears mouth nose ")*2/" ")[.%22]' <<< 1000
knees
```
[On-line test](https://jqplay.org/jq?q=%28%28%28%22head%20shoulders%20%22%2b%22knees%20toes%20%22*2%29*2%2b%22eyes%20ears%20mouth%20nose%20%22%29*2/%22%20%22%29[.%2522]&j=1000) (Passing `-r` through URL is not supported – check Raw Output yourself.)
[Answer]
# WinDbg, ~~207~~ ~~157~~ 151 bytes
```
ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
```
*-50 bytes by encoding the offset/length of the body parts as ascii chars.*
*-6 bytes by using a local var when looking up the offset/length.*
Input is done with a value set in the pseudo-register `$t0`.
How it works:
```
* Initialization, writes this string at address 0x2000000. The nonsense after the body parts
* are the offsets and lengths of the body parts in the first part of the string, each of
* which is incremented by 0x41 to make it a printable ascii character.
ea 2000000 
        "headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";
* Display the output:
r$t4=(@$t0%16)*2+2000027
da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
* Display output explanation:
r $t4 = (@$t0%16)*2+2000027   * Set $t4 = input, @$t0, mod 22, doubled +0x2000027
by(@$t4)                      * byte_at(@$t4)-0x41 is the {Offset} into the string 
                              * for the start of output. The -0x41 is already subtracted
                              * from 0x2000000 to make 0x1FFFFBF.
Lby(@$t4+1)-41                * byte_at(@$t4+1)-0x41 is the {Length} of the output.
da 1FFFFBF+{Offset} L{Length} * Display {Length} chars from {Offset} of the above string.
```
Sample output:
```
0:000> r$t0=0
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
02000000  "head"
0:000> r$t0=1
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
02000004  "shoulders"
0:000> r$t0=7
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
02000004  "shoulders"
0:000> r$t0=0n13
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
0200001a  "ears"
0:000> r$t0=0n20
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
0200000d  "knees"
0:000> r$t0=0n35
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
0200001a  "ears"
0:000> r$t0=0n37
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
02000023  "nose"
0:000> r$t0=0n98
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
0200000d  "knees"
0:000> r$t0=0n543
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
02000023  "nose"
0:000> r$t0=0n1000
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
0200000d  "knees"
```
[Answer]
# PHP, 91 ~~102~~ ~~118~~ ~~128~~ ~~129~~ Bytes
```
<?=[head,shoulders,knees,toes,eyes,ears,mouth,nose]['0123230123234567012323'[$argv[1]%22]];
```
0-Indexed
Down to 91 following removal of str\_split, didn't realise PHP string were accessible as a char array (a PHP 5+ thing?)
~~Down to 102 thanks to insertusername suggestion for removing string quotes and allowing the notices~~
[Answer]
# [Jelly](http://github.com/DennisMitchell/jelly), 55 bytes
```
“¥ḷne“¥ṇṭḲ»ẋ2ṭ“¢1$“@⁼5⁼»µẋ2;“¥ḳVo“¥ḳ'k“£Qo“£³ạ»;⁸FḊḲ
ị¢
```
[Try it online!](//jelly.tryitonline.net#code=4oCcwqXhuLduZeKAnMKl4bmH4bmt4biywrvhuosy4bmt4oCcwqIxJOKAnEDigbw14oG8wrvCteG6izI74oCcwqXhuLNWb-KAnMKl4bizJ2vigJzCo1Fv4oCcwqPCs-G6ocK7O-KBuEbhuIrhuLIK4buLwqI&args=MTAwMQ) (1-based index)
Come on! Really?
As a bonus, this is the compressed string I was supposed to use instead of the top line:
```
“¡¦ṡb[wfe=⁺żɦ4Gƈġhḳ"ẇ⁴ż>oH¹8ṡʠʠḟṀUṿḶ>¬Þ:ĖẇrṗṁɼlDṫỤ¬ȷ⁶Dḥci*⁻³GḲOÞạṖṃ\»
```
Both encode this string:
```
head shoulders knees toes knees toes head shoulders knees toes knees toes eyes ears mouth nose head shoulders knees toes knees toes
```
Guess I should go exercise now :P
[Answer]
## Powershell, 91 Bytes, Zero-Indexed
```
$a='head shoulders '+'knees toes '*2;($a*2+'eyes ears mouth nose '+$a).Split()[$args[0]%22]
```
Very straightforward approach, generate the array of the first 22 items using some string multiplication where possible, by compiling them with spaces and splitting at the end. (splitting is 2 bytes shorter than the equivalent setup as an array) then just find the point in that array using the modulus of the input, not exactly interesting or language-specific.
Test Case:
```
PS C:\++\golf> 0..1000|%{.\hskt $_}
head
shoulders
knees
toes
knees
toes
head
shoulders
knees
toes
knees
toes
eyes
ears
mouth
nose
head
shoulders
knees
toes
knees
toes
head
shoulders
knees
toes
....
```
etc.
[Answer]
# ruby, 81 bytes
Lambda function using zero indexing.
```
->n{("head shoulders#{" knees toes "*2}eyes ears mouth nose".split*2)[n%22-6&15]}
```
**explanation**
We generate the following array, of which we use the first 16 elements, covering the correct lines 2,3,4 of the song:
```
%w{head shoulders knees toes knees toes
   eyes ears mouth nose
   head shoulders knees toes knees toes
   eyes ears mouth nose}                  #last 4 elements not used
```
We take n modulo 22 to reduce it to a single verse, then we subtract 6. Now the index 6 (for example) has been changed to 0 and points to the right word. Indicies 0..5 which point to the first line of the song are now negative. We use `&15` (identical to `%16` but avoids the need for brackets) to map the 1st line of the song to the 4th line. Thus index `0` -> `-6` -> `10`
**in test program**
```
f=->n{("head shoulders#{" knees toes "*2}eyes ears mouth nose".split*2)[n%22-6&15]}
#call as below to test index 0..43
44.times{|i|p f[i]}
```
[Answer]
# Befunge, ~~129~~ 119 bytes
0-indexed
```
&29+2*%:2/v>00p>%#7_v
+%2\-"/"g2<|<:-1g007<"head*shoulders*knees*toes*eyes*ears*mouth*nose"p00
02202246022>$$:>7#:%#,_@
```
[Try it online!](http://befunge.tryitonline.net/#code=JjI5KzIqJToyL3Y-MDBwPiUjN192CislMlwtIi8iZzI8fDw6LTFnMDA3PCJoZWFkKnNob3VsZGVycyprbmVlcyp0b2VzKmV5ZXMqZWFycyptb3V0aCpub3NlInAwMAowMjIwMjI0NjAyMj4kJDo-NyM6JSMsX0A&input=MTAwMA)
**Explanation**
As [Arnauld](https://codegolf.stackexchange.com/users/58563/arnauld) pointed out, the words come in pairs, so we have an index of just 11 values and then add the word number % 2 to get the appropriate word in the pair. The words are pushed onto the stack as a single string separated by asterisks to save space. We test for word breaks by taking the char value modulo 7, since only the asterisk is a multiple of 7.
```
&29+2*%               n = getint() % 22             // % 22 to ensure it's in range
:2/2g                 i = index_array[n/2]          // we use n/2 because words are paired
-"/"                  i -= '/'                      // convert from ASCII to 1-based value
\2%+                  i += n%2                      // get the correct word in the pair
00p                   index = i                     // save for later
"head*shoulders*knees*toes*eyes*ears*mouth*nose"    // push all the words onto the stack
700g1-:|              while (index-1 != 0) {        // the 7 is used in the drop loop   
  00p                   index = index-1             
  >%#7_                 do while (pop() % 7)        // drop up to the next '*' (%7==0)
                      }                    
$$                    pop();pop()                   // get rid of index and extra 7
: 7 % _               while ((c = pop()) % 7)       // output up to the next '*' (%7==0)
 > : ,                  putchar(c)
```
[Answer]
# SQL 2005 747 Bytes
Golfed:
```
GO
CREATE PROCEDURE H @n INT AS BEGIN IF NOT EXISTS(SELECT*FROM R)BEGIN INSERT INTO R VALUES('head')INSERT INTO R VALUES('shoulders')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('head')INSERT INTO R VALUES('shoulders')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('eyes')INSERT INTO R VALUES('ears')INSERT INTO R VALUES('mouth')INSERT INTO R VALUES('nose')INSERT INTO R VALUES('head')INSERT INTO R VALUES('shoulders')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')END SELECT W FROM R WHERE I=@n%22 END
```
Ungolfed:
```
GO
CREATE PROCEDURE H
@n INT 
AS 
BEGIN IF NOT EXISTS(SELECT*FROM R)
BEGIN 
INSERT INTO R VALUES('head')INSERT INTO R VALUES('shoulders')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('head')INSERT INTO R VALUES('shoulders')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('eyes')INSERT INTO R VALUES('ears')INSERT INTO R VALUES('mouth')INSERT INTO R VALUES('nose')INSERT INTO R VALUES('head')INSERT INTO R VALUES('shoulders')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')
END 
SELECT W FROM R WHERE I=@n%22 END
```
Needs a table like this, where the first column is auto-incremented:
[![enter image description here](https://i.stack.imgur.com/rRpjB.png)](https://i.stack.imgur.com/rRpjB.png)
This is a one-indexed answer. The table is populated the first time stored procedure is created - it wouldn't let me do all the `INSERT` in one statement, disappointingly, this feature is only available in `>=SQL 2008`. After this, it uses the `%22` trick from the other answers. Once the table has been populated, it only uses the last part:
```
SELECT W FROM R WHERE I=@n%22
Input:  Output:
R 1       head
R 2       shoulders
R 8       shoulders
R 14      ears
R 21      knees
R 36      ears
R 38      nose
R 99      knees
R 54      nose
R 1001    knees
```
[Answer]
## bash (with ed), 83 chars
1-indexed
```
ed<<<"a
head
shoulders
knees
toes
eyes
ears
mouth
nose
.
3,4t4
1,6y
6x
$(($1%22))"
```
Sample call:
```
 $ bash test.sh 1001
 knees
```
[Answer]
# [dc](https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html), 135 bytes
```
6[head]6[:add6-r;ar:adA+r;ar:a]dshx7[shoulders]7lhx8[knees]8lhxA 2;aAlhx9[toes]9lhxB 3;aBlhx[eyes]C:a[ears]D:a[mouth]E:a[nose]F:a22%;ap
```
[Try it online!](https://tio.run/##Jc/NasMwEATge59iIeRUCrLV@LcXJ23PvQtRlmhbmSrr4LWp0pd3F3L7ZmAOE87b4dlulYuEwVeuwxCqp7nHWTU83uGDxFw7idOaAs3i6xRz436YSHyjHqDscVC0bpm0a5VHsD0eFY5uWp06dIS6fVVcpnWJ/k3Fk5B/77As9z1eNxfYdeD5HuXzr3jJXjLsZLxc0/h1g3llHvkbFpIFzigkD4X5gB3TbxqZNBgDegnaBmwN9gClgcJCDQUYSDlv/w "dc – Try It Online")
Arrays in `dc` have to be built an element at a time, which takes up the brunt of this exercise. Since 'eyes', 'ears', 'mouth', and 'nose' only appear once in our array, we just pop them in. But for the others, we save a few bytes by putting them on the stack like `x[head]x`, where *x* is the middle of its three values, then we run the macro `[:add6-r;ar:adA+r;ar:a]dshx` to put it in the array, pull it back, put it in at the same value less six, pull it back, and then put it in one last time at the original value plus ten. We use the middle value because `dc` allows us to use hex digits even in decimal mode, and subtracting `A` is one less byte than adding `16` - this also only works because all of the middle values are under fifteen. We have to do knees and toes twice, and making our macro smart enough to sort that out is more expensive than just running the macro twice; but we do save bytes here by loading a previously stored copy of the string instead of writing it out again (`B 3;aB` vs. `B[toes]B` - I think this saves 3 bytes total).
Once we have the array built, all we need to do is `22%` and then `;ap` to pull it from the array and print. 
[Answer]
## C#6, 138 bytes
```
string F(int i)=>(i+10)%22<4?"eyes,ears,mouth,nose".Split(',')[(i+10)%22%4]:"head,shoulders,knees,toes,knees,toes".Split(',')[(i+6)%22%6];
```
[repl.it demo](https://repl.it/E2SC/1)
Ungolfed + comments:
```
string F(int i)=>
    // Is it eyes/ears/mouth/nose?
    (i+10)%22<4
        // If yes, then set index to 4-word line and take modular 4
        // String array constructed by splitting comma-delimited words
        ? "eyes,ears,mouth,nose".Split(',')
            [(i+10)%22%4]
        // Else set index to last 6-word line and take modular 6
        : "head,shoulders,knees,toes,knees,toes".Split(',')
            [(i+6)%22%6];
```
[Answer]
# Excel, 146 bytes
```
=MID("Head     ShouldersKnees    Toes     Eyes     Ears     Mouth    Nose",CHOOSE(MOD(MOD(MOD(B1+16,22),16),10)+1,1,10,19,28,19,28,37,46,55,64),9)
```
Uses @Neil's `MOD(MOD(MOD(B1+16,22),16),10)` to save `15` bytes.
]