Using the Pipe Operator - String replace in multiple files


The unix command line is a wonderful thing. It allows us to string many commands together by use of a pipe. For example, if I want to find all python files, I could type

>find . -name "*.py"

Now one thing that causes issues in python is when some developers use tabs and others use spaces. I think tabs are better, but as you can't mix spaces and tabs in the same python file, and spaces are considered the standard way of using python, I use spaces. So what do you do if someone has written their code using tabs, and you only find out when you have "unexpected indent" errors when you come to run your code. Well, say your file is, you can use perl to replace the tabs with spaces as follows;

>perl -p -i -e "s/\t/    /g"

So say you have hundreds of python files in a large django project. Some have spaces, some have tabs. What do you do. Well, you need to use unix pipe to send output from the find command to the perl command. May be this will work:

>find . -name "*.py" |  perl -p -i -e "s/\t/    /g"

This does not work! Why? The trouble is, the pipe operator sends the result of the preceding statement to be used as direct input for the next. In this case find returns all the file names with a .py extension, and then the perl command takes these file names, and replaces any tabs in the file names with four spaces. What we want is for the files belonging to the filenames out put from find to be used by the perl function. To do this we need to use xargs, and to be doubly sure that the correct output is used, we use the print directive as follows:

>find . -name "*.py" -print0 | xargs -0 perl -p -i -e "s/\t/    /g"

and viola! all your pesky tabs are now turned into four consecutive spaces in every file with a .py extension.

Currently unrated


There are currently no comments

New Comment


required (not published)