ディレクトリのすべてのファイルでタブをスペースに変換するにはどうすればよいですか(再帰的に)。
また、タブごとのスペース数を設定する方法はありますか?
警告:これはリポジトリを壊すでしょう。
svn
、.git
の下にあるものも含めて、これはバイナリファイルを破壊するでしょう!使用する前にコメントを読んでください。
find . -type f -exec sed -i.orig 's/\t/ /g' {} +
元のファイルは[filename].orig
として保存されます。
欠点:
sed
で単純に置き換えることは問題ありませんが、最善の解決策ではありません。タブの間に「余分な」スペースがあると、置換後もスペースが残りますので、余白が不揃いになります。行の途中で展開されたタブも正しく機能しません。 bash
では、代わりに言うことができます
find . -name '*.Java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
現在のディレクトリツリー内のすべてのJavaファイルにexpand
を適用します。他の種類のファイルをターゲットにしている場合は、-name
引数を削除または置き換えます。コメントの1つが述べているように、-name
を削除するとき、または弱いワイルドカードを使用するときは非常に注意してください。意図せずにリポジトリやその他の隠しファイルを簡単に削除することができます。これが元の答えがこれを含んでいた理由です:
何か問題が発生した場合に備えて、このようなことを試す前に必ずツリーのバックアップコピーを作成してください。
Gene's answer から最良のコメントを収集する、これまでのところ最良の解決策は、 moreutils からsponge
を使用することです。
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
から)標準入力を取り込み、ファイル(同じもの)に書き込みます*。NOTE:*単純なファイルリダイレクト(> "$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
再帰的アプリケーションのための上の "find"の例が好きです。ワイルドカードに一致する現在のディレクトリ内のファイルを変更するだけで、再帰的でないようにそれを適応させるために、シェルグロブ展開は少量のファイルに対して十分であることができます:
ls *.Java | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh -v
それが機能すると信頼した後にそれを静かにしたければ、最後にsh
コマンドに-v
をドロップするだけです。
もちろん、最初のコマンドで任意のファイルセットを選ぶことができます。たとえば、特定のサブディレクトリ(複数可)のみを、次のように制御された方法でリストします。
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
一般的に入手可能な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
バイナリファイルをスキップするためのロジックは この投稿 からです。
注:
ディレクトリのすべてのファイルでタブをスペースに変換するにはどうすればよいですか(おそらく再帰的に)?
これは通常、not欲しいものです。
PNG画像に対してこれを実行しますか? PDFファイル? .gitディレクトリ?あなたのMakefile
(どのにタブが必要ですか)? 5GB SQLダンプ?
理論的には、find
など、使用している他のすべてに多くの除外オプションを渡すことができます。しかし、これは壊れやすく、他のバイナリファイルを追加するとすぐに壊れます。
あなたが欲しいものは、少なくともです:
expand
はこれを行いますが、sed
は行いません)。私の知る限り、これを実行できる「標準」のUnixユーティリティはなく、シェルワンライナーを使用するのは非常に簡単ではないため、スクリプトが必要です。
少し前に sanitize_files という小さなスクリプトを作成しました。また、\r\n
を\n
で置き換える、末尾の\n
などを追加するなど、その他の一般的な問題も修正します。
簡単なスクリプトを追加の機能とコマンドライン引数なしで見つけることができますが、この投稿よりもバグ修正やその他の更新を受け取る可能性が高いため、上記のスクリプトを使用することをお勧めします。
また、ここでの他の回答のいくつかに応えて、シェルグロビングを使用することはnotこれを行うための堅牢な方法であることを指摘したいと思います遅かれ早かれ、あなたはARG_MAX
に収まるよりも多くのファイルになります(現代のLinuxシステムでは128kで、多くのように見えるかもしれませんが、遅かれ早かれnot 十分な)。
#!/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 __== '__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)
タブの代わりに4つのスペースを使用するように、ディレクトリ内のすべてのJavaファイルを再帰的に変換するには、次のようにします。
find . -type f -name *.Java -exec bash -c 'expand -t 4 {} > /tmp/stuff;mv /tmp/stuff {}' \;
find
を tabs-to-spaces
パッケージと一緒に使うことができます。
最初にtabs-to-spaces
をインストールしてください
npm install -g tabs-to-spaces
次に、プロジェクトのルートディレクトリからこのコマンドを実行します。
find . -name '*' -exec t2s --spaces 2 {} \;
これにより、すべてのファイル内のすべてのtab
文字が2つのspaces
に置き換えられます。
次のスクリプトをダウンロードして実行し、プレーンテキストファイルでハードタブをソフトタブに再帰的に変換します。
プレーンテキストファイルを含むフォルダの中からスクリプトを実行します。
#!/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;
私は astyle
を使用して、タブとスペースが混在している場合にC/C++コードをすべて再インデントしました。必要に応じて特定のブレーススタイルを強制するオプションもあります。
私のお勧めは、
find . -name '*.lua' -exec ex '+%s/\t/ /g' -cwq {} \;
コメント:
sed
はストリームエディタです。インプレース編集にはex
を使用してください。これにより、 トップアンサー のように、余分な一時ファイルを作成したり、置き換えごとにシェルを生成したりする必要がなくなります。find|xargs
の代わりにfind -exec
を使用していました。 @ gniourf-gniourfで指摘されているように、これはファイル名cfのスペース、引用符、制御文字に関する問題を引き起こします。 ウィーラー 。そのためにvim
を使うことができます。
find -type f \( -name '*.css' -o -name '*.html' -o -name '*.js' -o -name '*.php' \) -execdir vim -c retab -c wq {} \;
Carpetsmokerが述べたように、それはあなたのvim
の設定に従って再配置されます。そして、もしあればファイル内のモデル化します。また、行の先頭だけでなくタブも置き換えられます。これはあなたが一般的に欲しいものではありません。たとえば、タブを含むリテラルがあるかもしれません。
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 残念ながらI 簡潔なPOSIXの代替方法 が見つかりません。
あなたのコードベースが文字列で機能的な生のタブを許可するという狂った考えを持っていたならば、:
expand -i
次に、行頭以外のすべてのタブを1つずつ試してみてください。 grepのタブをgitすることはできますか?
Ubuntu 18.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