Bash Sort

From time to time, we got some code challenge / codekata at work. The concept is simple it’s just some simple problem to sovles so that we can share. I usualy do one version in a language like Scala, Python or other more or less fancy language like C++ or even Haskell but I also try to have a Bash version, with extra point if I can oneline it.

Here it was about sorting Star Wars movies from their story chronological order starting from a list with the release order.

## Generation of files ##

cat > movies.txt <<EOL
A New Hope (1977)
The Empire Strikes Back (1980)
Return of the Jedi (1983)
The Phantom Menace (1999)
Attack of the Clones (2002)
Revenge of the Sith (2005)
The Force Awakens (2015)
Rogue One: A Star Wars Story (2016)
The Last Jedi (2017)
Solo: A Star Wars Story (2018)
EOL

cat > order.txt <<EOL
4 
5
6
10
8
1
2
3
7
9
EOL

cat > expect.txt <<EOL
The Phantom Menace (1999)
Attack of the Clones (2002)
Revenge of the Sith (2005)
Solo: A Star Wars Story (2018)
Rogue One: A Star Wars Story (2016)
A New Hope (1977)
The Empire Strikes Back (1980)
Return of the Jedi (1983)
The Force Awakens (2015)
The Last Jedi (2017)
EOL

Each line of order.txt tells which line of movies.txt to substitute so we can’t just paste order.txt movies.txt | sort -n because we need to find a way to extract the nth line of the movies.txt

To do that, we can use sed -n "Np" file, N is the line number to get, p is the sed command to “print”. -n is needed as by default, sed will print the file anyway.

totetmatt$ sed -n 10p movies.txt

Solo: A Star Wars Story (2018)

We can then wire this with the output of the order.txt via a pipeline and a xargs. Let’s also add a tee at the end so it stores the result in a file while keeping the possibilites to use the output for other operation.

cat order.txt  | xargs -I % sed -n "%p" movies.txt  |  tee result.txt

The Phantom Menace (1999)
Attack of the Clones (2002)
Revenge of the Sith (2005)
Solo: A Star Wars Story (2018)
Rogue One: A Star Wars Story (2016)
A New Hope (1977)
The Empire Strikes Back (1980)
Return of the Jedi (1983)
The Force Awakens (2015)
The Last Jedi (2017)

We could add some automated check to be sure the operation works as expected. Good solution will be to use diff result.txt expect.txt as we have 2 files generated. But let’s say that we don’t have the result.txt , only the command output and still want to use the diff that only accept file as input.

We can then use <(command) to concider the whole command output as an input file for diff.

diff <(cat order.txt  | xargs -I % sed -n "%p" movies.txt | tee result.txt) expect.txt || echo "No ok"

https://gist.github.com/totetmatt/2b4c74eb214fcc6d04ffcd39bdbd43ad