ディレクトリのすべてのファイルでタブをスペースに変換するにはどうすればよいですか(おそらく再帰的に)。
また、タブごとのスペースの数を設定する方法はありますか?
pr
これは素晴らしいユーティリティです。この回答を参照してください。
ディレクトリのすべてのファイルでタブをスペースに変換するにはどうすればよいですか(おそらく再帰的に)。
また、タブごとのスペースの数を設定する方法はありますか?
pr
これは素晴らしいユーティリティです。この回答を参照してください。
回答:
警告:これはリポジトリを壊します。
この意志破損したバイナリファイルを、それらの下を含め、
svn
、.git
!使用する前にコメントを読んでください!
find . -iname '*.java' -type f -exec sed -i.orig 's/\t/ /g' {} +
元のファイルはとして保存され[filename].orig
ます。
「* .java」を、探しているファイルタイプの末尾で置き換えます。これにより、バイナリファイルの偶発的な破損を防ぐことができます。
欠点:
find ./ -type f -exec sed -i 's/^\t/####/g' {} \;
。しかし、私はエキスパンドコマンドを認識していませんでした-とても便利です!
での単純な置き換えsed
は問題ありませんが、最善の解決策ではありません。タブの間に「余分な」スペースがある場合、タブは置換後も存在するため、マージンは不揃いになります。行の途中で展開されたタブも正しく機能しません。ではbash
、代わりに
find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
expand
現在のディレクトリツリー内のすべてのJavaファイルに適用します。-name
他のファイルタイプをターゲットにしている場合は、引数を削除または置き換えます。コメントの1つが言及しているように-name
、弱いワイルドカードを削除または使用するときは十分注意してください。意図せずに、リポジトリやその他の隠しファイルを簡単に上書きできます。これが、元の回答にこれが含まれていた理由です。
何か問題が発生した場合に備えて、このようなことを試みる前に、必ずツリーのバックアップコピーを作成してください。
{}
。彼は$0
いつ-c
使用されるのか知りませんでした。次に、dimo414は、変換ディレクトリでのtempの使用からに変更されました/tmp
。これ/tmp
は、が別のマウントポイントにある場合、はるかに遅くなります。残念ながら、私はあなたの$0
提案をテストするために利用できるLinuxボックスを持っていません。しかし、私はあなたが正しいと思います。
find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
sponge
からjoeyh.name/code/moreutilsは、あなたが書くことができますfind . -name '*.py' ! -type d -exec bash -c 'expand -t 8 "$0" | sponge "$0"' {} \;
find . -name '*'
ローカルのgitレポを破壊しただけです
コマンドラインツールをお試しくださいexpand
。
expand -i -t 4 input | sponge output
どこ
-i
各行の先頭のタブのみを展開するために使用されます。-t 4
各タブが4つの空白文字(デフォルトでは8)に変換されることを意味します。sponge
moreutils
パッケージからのものであり、入力ファイルの消去を回避します。最後に、Homebrew()でgexpand
インストールcoreutils
した後、OSXで使用できますbrew install coreutils
。
-i
てexpand
、各行の先頭のタブのみを置き換える必要があります。これにより、コードの一部である可能性のあるタブの置き換えを回避できます。
input
と同じファイルの場合、output
開始する前にコンテンツを上書きしますexpand
。これがどのように>
機能するかです。
Geneの回答から最高のコメントを収集することは、これまでで最高のソリューションでありsponge
、moreutilsを使用することです。
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
すべてのタブを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
sed -i '' $'s/\t/ /g' $(find . -name "*.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
バイナリファイルをスキップするロジックは、この投稿にあります。
注意:
expand
どちらもPOSIXであることを考えると、何か利点はありますか?たとえば、インライン変更オプションはありますか?Gitの安全性:stackoverflow.com/a/52136507/895245
ディレクトリのすべてのファイルでタブをスペースに変換するにはどうすればよいですか(おそらく再帰的に)。
これは通常はありませんあなたが欲しいもの。
これをpng画像に実行しますか?PDFファイル?.gitディレクトリ?あなたの
Makefile
(タブが必要です)?5GB SQLダンプ?
理論的には、exludeオプションの多くを、使用しfind
ている他のオプションに渡すことができます。しかし、これは壊れやすく、他のバイナリファイルを追加するとすぐに壊れます。
あなたが欲しいのは少なくとも:
expand
これはsed
行いますが、行いません)。私の知る限り、これを実行できる「標準」のUNIXユーティリティはなく、シェルの1ライナーを使用して実行するのは簡単ではないため、スクリプトが必要です。
少し前に、まさにそれを行う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)
上記の再帰的なアプリケーションの「検索」の例が好きです。これを非再帰的で、ワイルドカードに一致する現在のディレクトリ内のファイルのみを変更するように適合させるには、シェルグロブ拡張で少量のファイルを十分に処理できます。
ls *.java | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh -v
動作すると信頼した後でサイレントにしたい場合-v
は、sh
コマンドのonを最後にドロップしてください。
もちろん、最初のコマンドでファイルのセットを選択できます。たとえば、次のように制御された方法で特定のサブディレクトリのみを一覧表示します。
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
ARG_MAX
長さは長さのみであるため、シェルグロビングは遅かれ早かれ中断します。これはLinuxシステムでは128kですが、シェルグロビングに依存しないようにするのに十分な回数この制限に遭遇しました。
find
語らすることができ-maxdepth 1
、そしてそれだけで変更されているディレクトリのエントリではなく、ツリー全体を処理します。
そのために使用できますvim
:
find -type f \( -name '*.css' -o -name '*.html' -o -name '*.js' -o -name '*.php' \) -execdir vim -c retab -c wq {} \;
Carpetsmokerが述べたように、それはあなたのvim
設定に従って再タブ化します。そして、もしあればファイルのモードライン。また、行の最初だけでなくタブも置き換えます。これは一般的には望んでいないことです。たとえば、タブを含むリテラルがあるとします。
:retab
最初のタブではなく、ファイル内のすべてのタブを変更します。また、vimrcやモードラインでの設定:tabstop
や:expandtab
設定に依存するため、これがまったく機能しない場合があります。
tabstop
とexpandtab
設定については、を使用している場合はうまくいきますvim
。ファイルにモード行がない場合。
私の推奨は、使用することです:
find . -name '*.lua' -exec ex '+%s/\t/ /g' -cwq {} \;
コメント:
sed
ストリームエディタです。ex
インプレース編集に使用します。これにより、トップの回答にあるように、余分な一時ファイルを作成したり、置換ごとにシェルを生成したりする必要がなくなります。find|xargs
代わりに使用されたこの回答の以前のバージョンfind -exec
。@ gniourf-gniourfで指摘されているように、これはファイル名cfのスペース、引用符、制御文字に関する問題を引き起こします。ウィーラー。ex
すべてのUnixシステムで利用できるとは限りません。で置き換えると、vi -e
より多くのマシンで動作する可能性があります。また、正規表現は、任意の数の開始タブ文字を2つのスペースに置き換えます。+%s/\t/ /g
マルチレベルのインデントを破壊しないように正規表現を置き換えます。ただし、これはインデントに使用されないタブ文字にも影響します。
/\t/ /
にファイルでバリアントを使用していましたが、/\t\+//
インデントしないタブを壊さないことを選択しました。マルチインデントの問題を見逃しました!回答の更新。[1] man7.org/linux/man-pages/man1/ex.1p.html#SEE%C2%A0ALSO
xargs
この方法での使用は、役に立たず、非効率的で、壊れています(スペースまたは引用符を含むファイル名を考えてください)。代わりにfind
の-exec
スイッチを使用しないのはなぜですか?
-print0
/ xargsを見つけるためのオプション。-exec
以来、私はxargsが好きです。
タブの代わりに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
に置き換えられます。
ボディは言及されていません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
次のスクリプトをダウンロードして実行し、プレーンテキストファイルのハードタブをソフトタブに再帰的に変換します。
プレーンテキストファイルを含むフォルダー内からスクリプトを実行します。
#!/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の選択肢を見つけることができません。
コードベースに文字列で機能的な生のタブを許可するというクレイジーなアイデアがある場合は、以下を使用します。
expand -i
次に、行の先頭以外のすべてのタブを1つずつ確認していきます。これを次のように表示できます。タブのgit grepを実行できますか?
Ubuntu 18.04でテスト済み。
".lua"ファイル内のタブをスペースに変換する[タブ-> 2つのスペース]
find . -iname "*.lua" -exec sed -i "s#\t# #g" '{}' \;
expand -t 4 input >output
)
expand -t 4
タブがa\tb
3スペースに、タブがaa\tb
2スペースに拡張されます。expand
タブのコンテキストを考慮に入れますが、コンテキストにsed
関係なく、指定したスペースの量でタブを置き換えません。
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 $*
}
:retab
ていない可能性のあるすべての作業を、シェルグロブは、この種のもののための悪いソリューションで、あなたの:s
コマンドは置き換えられます任意のあなたの2つのスペースとタブの量を(そのほとんど:!expand
プロセスを実行するためだけにexを開始するのは馬鹿げています...