Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a lot of files with tabs littered throughout, and I'd like to convert them all into spaces. I know about the expand command, but unfortunately I would have to type out every single file using it. Is there any easier way to do this on Linux?

share|improve this question

Try the following:

find ./ -type f -exec sed -i 's/\t/ /g' {} \;

If you want four spaces, try:

find ./ -type f -exec sed -i 's/\t/    /g' {} \;
share|improve this answer
That will replace each tab by a single space. Since person mentioned using expand, I assume s/he wants the alignment of the text preserved. – garyjohn Jul 2 '10 at 5:27
You need to have 's/\t/ /g' to replace more than just one tab per line. – Daniel Andersson Mar 28 '12 at 20:49
@DanielAndersson: Thanks, edited! – Nicolas Raoul Mar 29 '12 at 5:00
A substantial speedup if there are many files is doing "find ./ -type f -exec sed -i ’s/\t/ /g’ {} +" (that is, "+" instead of "\;"), if the find version supports it (and I haven't personally met any version that doesn't, but it's not a POSIX standard, so I guess it could happen on some systems. See "-exec command {} +" in the manual). Instead of launching one instance of sed for every file, this will build an argument list with as many file name arguments as the system supports (getconf ARG_MAX=2097152 on my system), just like xargs, and thus launch much fewer sed processes. – Daniel Andersson Mar 29 '12 at 6:43
Note to any Mac users who find this: OS X's version of sed doesn't understand the \t tab escape sequence. You can replace it with a literal tab character, which you can enter in the shell by [Ctrl]+V, [Tab]. – This Site is Terrible Dec 17 '12 at 20:44

There are lots of ways to do this. There are also lots of ways to shoot yourself in the foot while doing this if you're not careful or if you're new to Linux as you appear to be. Assuming that you can create a list of files that you want to convert, either by using something like find or manually with an editor, just pipe that list into the following.

while read file
   expand "$file" > /tmp/expandtmp
   mv /tmp/expandtmp "$file"

One way you can shoot yourself in the foot with that is to make a typo so that you wind up mv'ing an empty file to all of the file names you specify, thereby deleting the contents of all your files. So be careful and test whatever you do first on a small set of files that you have backed up.

share|improve this answer
Make the mv conditional on the success of expand: expand ... && mv ... – Dennis Williamson Jul 2 '10 at 10:04
Don't forget expand -t 4 to expand tabs to 4 spaces. Also, this method can create trailing newlines. But otherwise it works. – mgold Sep 13 '14 at 19:02
find . -type f -iname "*.js" -print0 | xargs -0 -I foo tab2space foo foo

-I foo creates a template variable foo for each input line, so you can refer to the input more than once.

-print0 and -0 tell both commands to use \0 as a line separator instead of SPACE, so this command works for paths with spaces.

share|improve this answer

This is better:

find . -name *.java ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
share|improve this answer
Why is this better? It's not a great idea to use /tmp/e because if anything else is using that file, this will mess it up. Like if two users wanted to use this at the same time. – Kevin Panko Mar 8 '14 at 17:35
find -name \*.js -exec bash -c 'expand -t 4 "$0" | tee "$0"' {} \;

files larger than the pipe buffer size (64KB) get truncated

no temp files
files larger than the pipe buffer size get truncated

share|improve this answer

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .