디렉토리의 모든 파일에서 탭을 공백으로 변환하려면 어떻게해야합니까 (재귀 적으로)?
또한 탭당 공백 수를 설정하는 방법이 있습니까?
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' {} \;
. 그러나 expand 명령을 알지 못했습니다. 매우 유용합니다!
간단한 교체 sed
는 가능하지만 최상의 솔루션은 아닙니다. 탭 사이에 "추가"공간이 있으면 교체 후에도 여백이 그대로 유지되므로 여백이 고르지 않게됩니다. 줄 중간에 확장 된 탭도 제대로 작동하지 않습니다. 에서 bash
대신 말할 수 있습니다.
find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
expand
현재 디렉토리 트리의 모든 Java 파일에 적용 합니다. -name
다른 파일 형식을 대상으로하는 경우 인수를 제거 / 바꾸십시오 . 주석 중 하나에서 언급했듯이 -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
에서 사용하면 다음 과 같이 작성할 수 있습니다.find . -name '*.py' ! -type d -exec bash -c 'expand -t 8 "$0" | sponge "$0"' {} \;
find . -name '*'
방금 로컬 git repo를 파괴했습니다
명령 행 도구를 사용해보십시오 expand
.
expand -i -t 4 input | sponge output
어디
-i
각 행에서 선행 탭만 확장하는 데 사용됩니다.-t 4
즉, 각 탭은 4 개의 공백 문자 (기본적으로 8 자)로 변환됩니다.sponge
는 moreutils
패키지에서 왔으며 입력 파일을 지우지 않습니다 .마지막으로 Homebrew ( )로 gexpand
설치 한 후 OSX에서 사용할 수 있습니다 .coreutils
brew install coreutils
-i
하는 expand
각 줄에 선도적 인 탭을 대체 할 수 있습니다. 이렇게하면 코드의 일부일 수있는 탭을 교체하지 않아도됩니다.
input
와 동일한 파일 인 output
경우 시작하기 전에 bash가 내용을 클로버 expand
합니다. 이것이 >
작동 하는 방식입니다.
지금까지 최고의 솔루션 인 Gene의 답변 에서 최고의 의견을 수집하는 것은 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
)을 흡수하고 파일 (같은 파일)에 씁니다. *.참고 : * 간단한 파일 리디렉션 ( > "$0"
)은 파일을 너무 빨리 덮어 쓰기 때문에 여기서 작동하지 않습니다 .
장점 : 모든 원본 파일 권한이 유지되고 중간 tmp
파일이 사용 되지 않습니다 .
백 슬래시로 이스케이프 처리하십시오 sed
.
리눅스에서 :
모든 * .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 page here )을 사용할 수 있습니다 . 예를 들어, 탭을 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라는 점에서 어떤 이점 이 있습니까? 예를 들어 인라인 변경 옵션이 있습니까? 힘내 안전 : stackoverflow.com/a/52136507/895245
디렉토리의 모든 파일에서 탭을 공백으로 변환하려면 어떻게해야합니까 (재귀 적으로)?
이것은 일반적으로 원하는 것이 아닙니다 .
png 이미지에 대해이 작업을 수행 하시겠습니까? PDF 파일? .git 디렉토리? 당신의
Makefile
( 필요한 탭 합니까)? 5GB SQL 덤프?
이론적으로는 많은 exlude 옵션을 전달할 수 있습니다. find
당신이 사용하는 다른 . 그러나 이것은 깨지기 쉽고 다른 바이너리 파일을 추가하자마자 깨질 것입니다.
당신이 원하는 것은 최소한 :
expand
그렇지 만 sed
그렇지 않습니다).내가 아는 한,이 작업을 수행 할 수있는 "표준"유닉스 유틸리티가 없으며, 쉘 one-liner로 수행하기가 쉽지 않으므로 스크립트가 필요합니다.
얼마 전에 나는 정확히 그렇게하는 sanitize_files 라는 작은 스크립트를 만들었습니다
. 또한로 대체 , 후행 추가 \r\n
와 같은 다른 일반적인 사항을 수정합니다.\n
\n
등
아래에 추가 기능과 명령 줄 인수가 없는 간단한 스크립트 를 찾을 수 있지만이 스크립트는 버그 수정 및이 게시물 이외의 다른 업데이트를받을 가능성이 높으므로 위의 스크립트를 사용하는 것이 좋습니다.
쉘 대체 (globbing)을 사용하는 것을 나는 또한처럼, 여기에 다른 몇 가지 답변에 대한 응답으로 지적하는 것 아니 이 일을 강력한 방법은 조만간 당신이 맞는 것보다 더 많은 파일로 끝날 것이기 때문에, 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
끝에 명령.
물론 첫 번째 명령에서 파일 세트를 선택할 수 있습니다. 예를 들어, 다음과 같이 제어 된 방식으로 특정 서브 디렉토리 (또는 디렉토리) 만 나열하십시오.
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이지만 셸 globbing에 의존하지 않을 정도로이 한계에 도달했습니다.
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 또는 modeline의 설정 :tabstop
및 :expandtab
설정 에 따라 다르 므로 전혀 작동하지 않을 수 있습니다.
tabstop
및 expandtab
설정, 당신이 사용하는 경우 밖으로 작동합니다 vim
. 파일에 모드 행이없는 한.
내 권장 사항은 다음을 사용하는 것입니다.
find . -name '*.lua' -exec ex '+%s/\t/ /g' -cwq {} \;
코멘트:
sed
스트림 편집기입니다. ex
현장 편집에 사용 합니다. 이렇게하면 맨 위 답변 에서와 같이 각 대체 파일에 대해 임시 파일과 생성 셸이 생성되지 않습니다 됩니다.find|xargs
대신에 사용 되었습니다 find -exec
. @ gniourf-gniourf가 지적한 것처럼 파일 이름 cf에 공백, 따옴표 및 제어 문자에 문제가 발생합니다. 휠러 .ex
모든 유닉스 시스템에서 사용 가능한 것은 아닙니다. 이를 대체하면 vi -e
더 많은 시스템에서 작동 할 수 있습니다. 또한 정규 표현식은 여러 개의 시작 탭 문자를 두 개의 공백으로 바꿉니다. +%s/\t/ /g
다단계 들여 쓰기를 제거하지 않기 위해 정규식을 바꾸십시오. 그러나 이것은 들여 쓰기에 사용되지 않는 탭 문자에도 영향을줍니다.
/\t/ /
파일 에서 변형을 사용 했지만 /\t\+//
들여 쓰기가 아닌 탭을 나누지 않기로 선택했습니다 . 다중 들여 쓰기와 관련된 문제를 놓쳤습니다! 답변 업데이트. [1] man7.org/linux/man-pages/man1/ex.1p.html#SEE%C2%A0ALSO
xargs
이 방법으로 사용 하는 것은 쓸모없고 비효율적이며 깨집니다 (공백 또는 따옴표가 포함 된 파일 이름을 생각하십시오). 왜 사용하지 find
의 -exec
대신 스위치를?
-print0
옵션 찾기 / xargs. 나는 xargs를 좋아한다 -exec
. a) 우려의 분리 b) GNU 병렬로보다 쉽게 교체 될 수있다.
디렉토리 대신 모든 Java 파일을 재귀 적으로 변환하여 탭 대신 4 개의 공백을 사용하려면 다음을 수행하십시오.
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 이상에서는 "inplace"파일과 같은 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-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
파일 권한을 변경하지 않고 유지합니다 : /unix/20645/clone-ownership-and-permissions-from-another-file 불행히도 간결한 POSIX 대안을 찾을 수 없습니다 .
코드베이스에 기능적인 원시 탭을 문자열로 허용하려는 아이디어가 있다면 다음을 사용하십시오.
expand -i
그런 다음 시작하지 않은 모든 라인 탭을 하나씩 차례로 살펴보면 다음과 같이 나열 할 수 있습니다 .
우분투 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
..tabstop을 수정하려면을 추가하십시오 +'set ts=2'
.
그러나 단점은 문자열 내부의 탭 을 바꿀 수 있다는 것 입니다.
따라서 대체를 사용하여 약간 더 나은 해결책을 얻으려면 다음을 시도하십시오.
$ ex -s +'bufdo %s/^\t\+/ /ge' -cxa **/*.*
또는 ex
editor + expand
utility 를 사용하여 :
$ 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
프로세스 를 실행하기 위해 예를 시작하는 것은 어리석은 일입니다 ...