
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