ディレクトリのすべてのファイルでタブをスペースに変換するにはどうすればよいですか(おそらく再帰的に)?
また、タブごとのスペース数を設定する方法はありますか?
との単純な交換sed
は問題ありませんが、最善の解決策ではありません。タブの間に「余分な」スペースがある場合、それらは置換後もそこにあるため、マージンは不規則になります。行の途中で展開されたタブも正しく機能しません。でbash
、代わりに言うことができます
find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
expand
現在のディレクトリツリー内のすべてのJavaファイルに適用します。-name
他のファイルタイプをターゲットにしている場合は、引数を削除/置換してください。-name
コメントの1つに記載されているように、弱いワイルドカードを削除または使用する場合は十分に注意してください。リポジトリやその他の隠しファイルを意図せずに簡単に壊してしまう可能性があります。これが、元の回答にこれが含まれている理由です。
何か問題が発生した場合に備えて、このようなことを試す前に、必ずツリーのバックアップコピーを作成する必要があります。
コマンドラインツールを試してくださいexpand
。
expand -i -t 4 input | sponge output
どこ
-i
各行の先頭のタブのみを展開するために使用されます。-t 4
これは、各タブが4つの空白文字(デフォルトでは8)に変換されることを意味します。sponge
moreutils
パッケージからのものであり、入力ファイルのクリアを回避します。macOSでは、パッケージはHomebrew()またはMacPorts( )moreutils
から入手できます。brew install moreutils
sudo port install moreutils
最後に、 Homebrew()またはMacPorts( )gexpand
でインストールcoreutils
した後、macOSで使用できます。brew install coreutils
sudo port install coreutils
警告:これにより、リポジトリが破損します。
これにより、、!の下にあるものを含むバイナリファイルが破損します。使用する前にコメントを読んでください!
svn
.git
find . -iname '*.java' -type f -exec sed -i.orig 's/\t/ /g' {} +
元のファイルはとして保存され[filename].orig
ます。
'* .java'を、探しているファイルタイプのファイル末尾に置き換えます。このようにして、バイナリファイルの偶発的な破損を防ぐことができます。
欠点:
Geneの回答から最高のコメントを収集することは、これまでで最高の解決策であり、frommoreutilssponge
を使用することです。
sudo apt-get install moreutils
# The complete one-liner:
find ./ -iname '*.java' -type f -exec bash -c 'expand -t 4 "$0" | sponge "$0"' {} \;
説明:
./
現在のディレクトリから再帰的に検索しています-iname
大文字と小文字を区別しない一致です(両方*.java
といいね*.JAVA
)type -f
通常のファイルのみを検索します(ディレクトリ、バイナリ、シンボリックリンクは検索しません)-exec bash -c
ファイル名ごとにサブシェルで次のコマンドを実行します。{}
expand -t 4
すべてのTABを4つのスペースに拡張しますsponge
標準入力(からexpand
)を吸収し、ファイル(同じもの)に書き込みます*。注:*単純なファイルリダイレクト(> "$0"
)は、ファイルの上書きが早すぎるため、ここでは機能しません。
利点:元のファイルのアクセス許可はすべて保持され、中間tmp
ファイルは使用されません。
バックスラッシュでエスケープされたを使用しますsed
。
Linuxの場合:
すべての*.txtファイルで、すべてのタブを1つのハイフンで置き換えます。
sed -i $'s/\t/-/g' *.txt
すべての*.txtファイルで、すべてのタブを1つのスペースで置き換えます。
sed -i $'s/\t/ /g' *.txt
すべての*.txtファイルで、すべてのタブを4つのスペースに置き換えます。
sed -i $'s/\t/ /g' *.txt
Macの場合:
すべての*.txtファイルで、すべてのタブを4つのスペースに置き換えます。
sed -i '' $'s/\t/ /g' *.txt
一般的に利用可能なpr
コマンド(manページはこちら)を使用できます。たとえば、タブを4つのスペースに変換するには、次のようにします。
pr -t -e=4 file > file.expanded
-t
ヘッダーを抑制します-e=num
タブをnum
スペースに展開しますバイナリファイルをスキップしながら、ディレクトリツリー内のすべてのファイルを再帰的に変換するには:
#!/bin/bash
num=4
shopt -s globstar nullglob
for f in **/*; do
[[ -f "$f" ]] || continue # skip if not a regular file
! grep -qI "$f" && continue # skip binary files
pr -t -e=$num "$f" > "$f.expanded.$$" && mv "$f.expanded.$$" "$f"
done
バイナリファイルをスキップするためのロジックは、この投稿からのものです。
ノート:
上記の再帰アプリケーションの「検索」の例が好きです。ワイルドカードと一致する現在のディレクトリ内のファイルのみを変更する非再帰的なものに適合させるには、少量のファイルに対してシェルグロブ拡張で十分な場合があります。
ls *.java | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh -v
動作すると確信した後でサイレントにしたい場合は、最後にコマンドをドロップして-v
くださいsh
。
もちろん、最初のコマンドで任意のファイルのセットを選択できます。たとえば、次のように制御された方法で特定のサブディレクトリ(または複数のディレクトリ)のみを一覧表示します。
ls mod/*/*.php | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh
または、深度パラメータなどを組み合わせてfind(1)を実行します。
find mod/ -name '*.php' -mindepth 1 -maxdepth 2 | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh
ディレクトリのすべてのファイルでタブをスペースに変換するにはどうすればよいですか(おそらく再帰的に)?
これは通常、あなたが望むものではありません。
png画像に対してこれを実行しますか?PDFファイル?.gitディレクトリ?あなたの
Makefile
(タブが必要です)?5GBのSQLダンプ?
理論的には、多くの除外オプションを、find
または使用している他のすべてのものに渡すことができます。しかし、これは壊れやすく、他のバイナリファイルを追加するとすぐに壊れます。
あなたが欲しいのは、少なくとも:
expand
が、sed
行いません)。私の知る限り、これを実行できる「標準の」Unixユーティリティはなく、シェルのワンライナーで実行するのは簡単ではないため、スクリプトが必要です。
少し前に、
sanitize_filesという小さなスクリプトを作成しました。これはまさにそれを実行します。\r\n
また、置換、\n
末尾の追加\n
など、その他の一般的なものも修正します。
以下に追加機能やコマンドライン引数のない簡略化されたスクリプトを見つけることができますが、バグ修正やこの投稿以外の更新を受け取る可能性が高いため、上記のスクリプトを使用することをお勧めします。
また、ここでの他のいくつかの回答に応えて、シェルグロブを使用することはこれを行うための堅牢な方法ではないことを指摘したいと思います。遅かれ早かれあなたはARG_MAX
(現代では)収まるよりも多くのファイルになってしまうからですLinuxシステムでは128kで、多くのように見えるかもしれませんが、遅かれ早かれそれだけでは
不十分です)。
#!/usr/bin/env python
#
# http://code.arp242.net/sanitize_files
#
import os, re, sys
def is_binary(data):
return data.find(b'\000') >= 0
def should_ignore(path):
keep = [
# VCS systems
'.git/', '.hg/' '.svn/' 'CVS/',
# These files have significant whitespace/tabs, and cannot be edited
# safely
# TODO: there are probably more of these files..
'Makefile', 'BSDmakefile', 'GNUmakefile', 'Gemfile.lock'
]
for k in keep:
if '/%s' % k in path:
return True
return False
def run(files):
indent_find = b'\t'
indent_replace = b' ' * indent_width
for f in files:
if should_ignore(f):
print('Ignoring %s' % f)
continue
try:
size = os.stat(f).st_size
# Unresolvable symlink, just ignore those
except FileNotFoundError as exc:
print('%s is unresolvable, skipping (%s)' % (f, exc))
continue
if size == 0: continue
if size > 1024 ** 2:
print("Skipping `%s' because it's over 1MiB" % f)
continue
try:
data = open(f, 'rb').read()
except (OSError, PermissionError) as exc:
print("Error: Unable to read `%s': %s" % (f, exc))
continue
if is_binary(data):
print("Skipping `%s' because it looks binary" % f)
continue
data = data.split(b'\n')
fixed_indent = False
for i, line in enumerate(data):
# Fix indentation
repl_count = 0
while line.startswith(indent_find):
fixed_indent = True
repl_count += 1
line = line.replace(indent_find, b'', 1)
if repl_count > 0:
line = indent_replace * repl_count + line
data = list(filter(lambda x: x is not None, data))
try:
open(f, 'wb').write(b'\n'.join(data))
except (OSError, PermissionError) as exc:
print("Error: Unable to write to `%s': %s" % (f, exc))
if __name__ == '__main__':
allfiles = []
for root, dirs, files in os.walk(os.getcwd()):
for f in files:
p = '%s/%s' % (root, f)
if do_add:
allfiles.append(p)
run(allfiles)
私の推奨事項は、以下を使用することです。
find . -name '*.lua' -exec ex '+%s/\t/ /g' -cwq {} \;
コメント:
sed
ストリームエディタです。ex
インプレース編集に使用します。これにより、トップアンサーのように、置換ごとに余分な一時ファイルを作成したり、シェルを生成したりする必要がなくなります。find|xargs
代わりに使用されましたfind -exec
。@ gniourf-gniourfが指摘しているように、これにより、ファイル名のスペース、引用符、および制御文字に問題が発生します。ウィーラー。find
このためのtabs-to-spaces
パッケージで使用できます。
まず、インストールしますtabs-to-spaces
npm install -g tabs-to-spaces
次に、プロジェクトのルートディレクトリからこのコマンドを実行します。
find . -name '*' -exec t2s --spaces 2 {} \;
tab
これにより、すべてのファイルですべての文字が2に置き換えspaces
られます。
以前astyle
は、タブとスペースが混在していることを見つけた後、すべてのC /C++コードを再インデントしていました。必要に応じて、特定のブレーススタイルを強制するオプションもあります。
そのために使用vim
することができます:
find -type f \( -name '*.css' -o -name '*.html' -o -name '*.js' -o -name '*.php' \) -execdir vim -c retab -c wq {} \;
Carpetsmokerが述べたように、設定に応じて再タブしvim
ます。そして、もしあれば、ファイルのモデライン。また、行頭だけでなくタブも置き換えられます。これはあなたが一般的に望んでいることではありません。たとえば、タブを含むリテラルがある場合があります。
ディレクトリ内のすべてのJavaファイルを再帰的に変換して、タブの代わりに4つのスペースを使用するには:
find . -type f -name *.java -exec bash -c 'expand -t 4 {} > /tmp/stuff;mv /tmp/stuff {}' \;
次のスクリプトをダウンロードして実行し、プレーンテキストファイルのハードタブをソフトタブに再帰的に変換します。
プレーンテキストファイルが含まれているフォルダ内からスクリプトを実行します。
#!/bin/bash
find . -type f -and -not -path './.git/*' -exec grep -Iq . {} \; -and -print | while read -r file; do {
echo "Converting... "$file"";
data=$(expand --initial -t 4 "$file");
rm "$file";
echo "$data" > "$file";
}; done;
Gitリポジトリに優しい方法
git-tab-to-space() (
d="$(mktemp -d)"
git grep --cached -Il '' | grep -E "${1:-.}" | \
xargs -I'{}' bash -c '\
f="${1}/f" \
&& expand -t 4 "$0" > "$f" && \
chmod --reference="$0" "$f" && \
mv "$f" "$0"' \
'{}' "$d" \
;
rmdir "$d"
)
現在のディレクトリの下にあるすべてのファイルを操作します。
git-tab-to-space
CまたはC++ファイルにのみ作用します。
git-tab-to-space '\.(c|h)(|pp)$'
タブを必要とする厄介なMakefileのために、これが特に必要になる可能性があります。
コマンドgit grep --cached -Il ''
:
.git
で説明されているように:gitリポジトリ内のすべてのテキスト(非バイナリ)ファイルを一覧表示するにはどうすればよいですか?
chmod --reference
ファイルのアクセス許可を変更せずに保持します:https ://unix.stackexchange.com/questions/20645/clone-ownership-and-permissions-from-another-file残念ながら、簡潔なPOSIXの代替手段が見つかりません。
コードベースに、文字列で機能的なrawタブを許可するというクレイジーなアイデアがあった場合は、次を使用します。
expand -i
次に、すべての非開始行タブを1つずつ確認して、リストに追加できます。タブのgrepをgitすることは可能ですか?
Ubuntu18.04でテスト済み。
言及された体はありませんrpl
か?rplを使用すると、任意の文字列を置き換えることができます。タブをスペースに変換するには、
rpl -R -e "\t" " " .
とてもシンプルです。
他の回答で提案されているように使用することはexpand
、このタスクだけで最も論理的なアプローチのようです。
とは言うものの、他の変更を一緒に実行したい場合に備えて、BashとAwkを使用して実行することもできます。
Bash 4.0以降を使用している場合は、shoptビルトイン globstar
を使用して。を使用して再帰的に検索できます**
。
GNU Awkバージョン4.1以降では、「インプレース」ファイル変更のようなsedを実行できます。
shopt -s globstar
gawk -i inplace '{gsub("\t"," ")}1' **/*.ext
タブごとのスペース数を設定する場合:
gawk -i inplace -v n=4 'BEGIN{for(i=1;i<=n;i++) c=c" "}{gsub("\t",c)}1' **/*.ext
「.lua」ファイル内のタブをスペースに変換する[タブ->2スペース]
find . -iname "*.lua" -exec sed -i "s#\t# #g" '{}' \;
vim-wayを使用します:
$ ex +'bufdo retab' -cxa **/*.*
globstar
( )を使用するには、でアクティブ化します。**
shopt -s globstar
**/*.c
。タブストップを変更するには、を追加し+'set ts=2'
ます。
ただし、欠点は、文字列内のタブを置き換えることができることです。
したがって、(置換を使用して)少し良い解決策を得るには、次のことを試してください。
$ ex -s +'bufdo %s/^\t\+/ /ge' -cxa **/*.*
または、ex
エディター+expand
ユーティリティを使用して:
$ ex -s +'bufdo!%!expand -t2' -cxa **/*.*
末尾のスペースについては、「複数のファイルの末尾の空白を削除する方法」を参照してください。
次の関数をに追加できます.bash_profile
:
# Convert tabs to spaces.
# Usage: retab *.*
# See: https://stackoverflow.com/q/11094383/55075
retab() {
ex +'set ts=2' +'bufdo retab' -cxa $*
}