How can I convert tabs to spaces in every file of a directory?

后端 未结 19 1216
既然无缘
既然无缘 2020-12-02 03:48

How can I convert tabs to spaces in every file of a directory (possibly recursively)?

Also, is there a way of setting the number of spaces per tab?

相关标签:
19条回答
  • 2020-12-02 03:52

    Use backslash-escaped sed.

    On linux:

    • Replace all tabs with 1 hyphen inplace, in all *.txt files:

      sed -i $'s/\t/-/g' *.txt
      
    • Replace all tabs with 1 space inplace, in all *.txt files:

      sed -i $'s/\t/ /g' *.txt
      
    • Replace all tabs with 4 spaces inplace, in all *.txt files:

      sed -i $'s/\t/    /g' *.txt
      

    On a mac:

    • Replace all tabs with 4 spaces inplace, in all *.txt files:

      sed -i '' $'s/\t/    /g' *.txt
      
    0 讨论(0)
  • 2020-12-02 03:53

    Simple replacement with sed is okay but not the best possible solution. If there are "extra" spaces between the tabs they will still be there after substitution, so the margins will be ragged. Tabs expanded in the middle of lines will also not work correctly. In bash, we can say instead

    find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
    

    to apply expand to every Java file in the current directory tree. Remove / replace the -name argument if you're targeting some other file types. As one of the comments mentions, be very careful when removing -name or using a weak, wildcard. You can easily clobber repository and other hidden files without intent. This is why the original answer included this:

    You should always make a backup copy of the tree before trying something like this in case something goes wrong.

    0 讨论(0)
  • 2020-12-02 03:53

    I like the "find" example above for the recursive application. To adapt it to be non-recursive, only changing files in the current directory that match a wildcard, the shell glob expansion can be sufficient for small amounts of files:

    ls *.java | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh -v
    

    If you want it silent after you trust that it works, just drop the -v on the sh command at the end.

    Of course you can pick any set of files in the first command. For example, list only a particular subdirectory (or directories) in a controlled manner like this:

    ls mod/*/*.php | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh
    

    Or in turn run find(1) with some combination of depth parameters etc:

    find mod/ -name '*.php' -mindepth 1 -maxdepth 2 | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh
    
    0 讨论(0)
  • 2020-12-02 03:53

    One can use vim for that:

    find -type f \( -name '*.css' -o -name '*.html' -o -name '*.js' -o -name '*.php' \) -execdir vim -c retab -c wq {} \;
    

    As Carpetsmoker stated, it will retab according to your vim settings. And modelines in the files, if any. Also, it will replace tabs not only at the beginning of the lines. Which is not what you generally want. E.g., you might have literals, containing tabs.

    0 讨论(0)
  • 2020-12-02 03:54

    Use the vim-way:

    $ ex +'bufdo retab' -cxa **/*.*
    
    • Make the backup! before executing the above command, as it can corrupt your binary files.
    • To use globstar (**) for recursion, activate by shopt -s globstar.
    • To specify specific file type, use for example: **/*.c.

    To modify tabstop, add +'set ts=2'.

    However the down-side is that it can replace tabs inside the strings.

    So for slightly better solution (by using substitution), try:

    $ ex -s +'bufdo %s/^\t\+/  /ge' -cxa **/*.*
    

    Or by using ex editor + expand utility:

    $ ex -s +'bufdo!%!expand -t2' -cxa **/*.*
    

    For trailing spaces, see: How to remove trailing whitespaces for multiple files?


    You may add the following function into your .bash_profile:

    # Convert tabs to spaces.
    # Usage: retab *.*
    # See: https://stackoverflow.com/q/11094383/55075
    retab() {
      ex +'set ts=2' +'bufdo retab' -cxa $*
    }
    
    0 讨论(0)
  • 2020-12-02 03:56

    To convert all Java files recursively in a directory to use 4 spaces instead of a tab:

    find . -type f -name *.java -exec bash -c 'expand -t 4 {} > /tmp/stuff;mv /tmp/stuff {}' \;
    
    0 讨论(0)
提交回复
热议问题