2

I have just inherited a new C++ project where plenty of files are indented with tabs while more recent ones are programmed with spaces. Now I want to change them all to using spaces only. Instead of going into every files and using EMacs auto-indent function, is there a more efficient way I could achieve it with bash?

Quang Thinh Ha
  • 239
  • 2
  • 10
  • OFC there is (are); e.g you could write a _for each_ + `sed` script...What have you tried so far? – danrodlor Jun 25 '19 at 15:18
  • Are the files all in one directory or in multiple subdirectories? – Cyrus Jun 25 '19 at 15:34
  • @cyrus the files are in multiple directories/subdirectories – Quang Thinh Ha Jun 25 '19 at 15:37
  • @danlor I was reserved about using `sed` due to the answer I found [here](https://stackoverflow.com/questions/11094383/how-can-i-convert-tabs-to-spaces-in-every-file-of-a-directory) – Quang Thinh Ha Jun 25 '19 at 15:38
  • What didn't work? – Cyrus Jun 25 '19 at 15:39
  • Then you can use `expand` or other similar tools. However, you can just filter the target files (only *.cpp) before piping them to `sed` in order to avoid making a huge mess of them. – danrodlor Jun 25 '19 at 15:46
  • 1
    Possible duplicate of [How can I convert tabs to spaces in every file of a directory?](https://stackoverflow.com/questions/11094383/how-can-i-convert-tabs-to-spaces-in-every-file-of-a-directory) – Léa Gris Jun 25 '19 at 16:02

3 Answers3

3

This will traverse the project files recursively and expand the tabs to spaces. Since I'm sure you're using source control, you can easily revert if something goes awry.

find /path/to/project -type f -name '*.cpp' -exec expand --initial {} +

The default is eight spaces, but you can use --tabs=4 or whatever value you want.

The --initial option ignores tabs which follow non blanks.

Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
1

I have two answers. First, to answer your specific question, I'd use perl or similar, like so:

replace-tab-indents.pl

#!/usr/bin/perl

while ($line = <STDIN>) {
    while ($line =~ /^ *\t/) {
        $line =~ s/^( *)\t/$1    /;
    }

    print(STDOUT $line);
}

This deals with only TABs at the start of the line. This is crucial to your use case, because you don't want to replace other TABs; e.g., those that are part of some static string in the code.

Use this inside of a shell script such as:

for FILE in `find . -name *.cpp`; do
    mv -i "$FILE" "$FILE.bak"
    cat "$FILE.bak" | replace-tab-indents.pl > "$FILE"
done

The use of the -name option on find limits you to just your source files, avoiding the problems that you correctly are wary of related to replacing all TABs in all files -- in many non-source files, the "TAB" byte is crucial to the data that comprises that file.

My second answer is to just change them as you go, instead of all at once.

This way you can employ emacs (or vim, or any modern editor, really), which will be a more tested, tried-and-true, robust approach.

The files compile just fine with TABs, so until you need to edit a given file, the presence of the TAB indentation does not affect you; at exactly the point in time when it affects you (i.e., the first time you edit it), you can use your editor to re-indent with spaces. In short, my advice here is to accomplish this just-in-time / as-you-go, not all-at-once.

Said differently, the compiler doesn't care about the indentation, only you do; and the only time you will care is when you actually edit a given source file; so, there is no empirical benefit from re-indenting your source files en mass.

landru27
  • 1,654
  • 12
  • 20
1

Using any solution using find one has to think about all possible filename extensions, looking at the GCC manual there are plenty of them.

Ack has a very good file selection option, just pass --cc as parameter to only match C++ files.

So, replace all tabs in all C++ files including header files use:

ack --cpp -l --print0 . | xargs -0 -n1 sed -i -e 's/\t/    /' 

ack will find all C++ files recursively in the current directory and pass only the file names to sed, which replaces all tabs with four spaces.

rkta
  • 3,959
  • 7
  • 25
  • 37