Some of my friends say that UNIX is beautiful and simple. But I really don't know what they mean. Why are they saying so? For me, UNIX is just a boring command prompt with different shells. How can I experience the beauty of UNIX? Can you share any experience?
One of the fundamental differences between UNIX and Windows, is that Windows tends to have complex monolithic applications, whereas UNIX achieves complexity by combining small, self-contained applications each of which is good at performing one specific task. In Windows, a particular application, no matter how rich and complex it can be, is all you have. In UNIX you can combine applications in many different ways to fit your needs. It is a completely different world, different way of thinking and working.
If you want to experience this you just have to work with UNIX for a while on specific tasks, it is difficult to appreciate it in the abstract. But here is a small example. Suppose you want to look for all C++ source files containing the macro USE64BIT. Here is one way (my way) of solving this on a UNIX system (specifically, on Ubuntu GNU/Linux 10.04).
To check if a file contains a string, I use grep. So I would write:
$ grep USE64BIT mysource.cpp
$ grep -H USE64BIT mysource.cpp
if I want to print the name of the matching file before each matching line.
Now, I want to find all C++ files, so I need a tool to search for files. I use find:
$ find . -name "*.cpp" -print
This will find all files with names matching the pattern *.cpp starting at the current directory (the first parameter '.') and print each file path (relative to .) on a separate line of output.
Fine, now I want to feed the output of find into grep to get all files containing my string. I have another tool: xargs. xargs can call another tool repeatedly, passing it as a parameter what it gets from standard input. So we need something like:
$ find ... -> xargs ... grep <input to xargs>
The above is not a valid command, but the idea is to pipe the result of find into xargs and let xargs call grep on each line of input. Here is a first solution:
$ find . -name "*.cpp" -print | xargs -iFILE grep -H USE64BIT FILE
Here, the output of find contains all the found files, one per line. xargs takes each line of input, sets the variable FILE to it, and calls grep repeatedly, each time passing it the current value of FILE as a parameter. The result of all these calls to grep is concatenated together to the final output stream.
This solution can still be improved: one should use -print0 in find and -0 in xargs so that the output from find uses a 0 character instead of newline as a separator (file names will never contain a 0 character, so 0 is a safer separator). So, the final solution is
$ find . -name "*.cpp" -print0 | xargs -0 -iFILE grep -H USE64BIT FILE
This is what we were looking for: all lines in all C++ files containing the given macro.
If you are not interested to see the matching lines, but just the files that match, you can change the option in the grep command. On GNU/Linux you can use -l to only print the file name of the matching file:
$ find . -name "*.cpp" -print0 | xargs -0 -iFILE grep -l USE64BIT FILE
Oh, but now you want to sort your list of matching file alphabetically. Fine:
$ find . -name "*.cpp" -print0 | xargs -0 -iFILE grep -l USE64BIT FILE | sort
And, of course, you could continue and invent more and more examples.
As you can see, every command is relatively simple and very specialized, but you can perform very complex tasks by combining different commands. You can drive the OS to get exactly what you want. This is for me one of the reasons why I appreciate UNIX systems so much because I haven't found this flexibility e.g. on Windows. First thing I do when I have to work on a Windows system is to install cygwin (a UNIX-like environment for Windows).