[bash] 디렉토리의 모든 파일에서 탭을 공백으로 변환하는 방법은 무엇입니까?
디렉토리의 모든 파일에서 탭을 공백으로 변환하려면 어떻게해야합니까 (재귀 적으로)?
또한 탭당 공백 수를 설정하는 방법이 있습니까?
답변
경고 : 이렇게하면 저장소가 손상됩니다.
이 손상됩니다 바이너리 파일 들에서 포함
svn
,.git
! 사용하기 전에 의견을 읽으십시오!
find . -iname '*.java' -type f -exec sed -i.orig 's/\t/ /g' {} +
원본 파일은로 저장됩니다 [filename].orig
.
‘* .java’를 찾고있는 파일 유형의 파일 끝으로 바꾸십시오. 이렇게하면 실수로 이진 파일이 손상되는 것을 방지 할 수 있습니다.
단점 :
- 파일의 모든 곳에서 탭을 대체합니다.
- 이 디렉토리에 5GB SQL 덤프가 있으면 시간이 오래 걸립니다.
답변
간단한 교체 sed
는 가능하지만 최상의 솔루션은 아닙니다. 탭 사이에 “추가”공간이 있으면 교체 후에도 여백이 그대로 유지되므로 여백이 고르지 않게됩니다. 줄 중간에 확장 된 탭도 제대로 작동하지 않습니다. 에서 bash
대신 말할 수 있습니다.
find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
expand
현재 디렉토리 트리의 모든 Java 파일에 적용 합니다. -name
다른 파일 형식을 대상으로하는 경우 인수를 제거 / 바꾸십시오 . 주석 중 하나에서 언급했듯이 -name
약한 와일드 카드를 제거 하거나 사용할 때 매우주의하십시오 . 의도없이 리포지토리 및 기타 숨겨진 파일을 쉽게 클로버 할 수 있습니다. 이것이 원래 답변에 다음이 포함 된 이유입니다.
무언가 잘못 될 경우를 대비하여 이와 같은 것을 시도하기 전에 항상 트리의 백업 사본을 만들어야합니다.
답변
명령 행 도구를 사용해보십시오 expand
.
expand -i -t 4 input | sponge output
어디
-i
각 행에서 선행 탭만 확장하는 데 사용됩니다.-t 4
즉, 각 탭은 4 개의 공백 문자 (기본적으로 8 자)로 변환됩니다.sponge
는moreutils
패키지에서 왔으며 입력 파일을 지우지 않습니다 .
마지막으로 Homebrew ( )로 gexpand
설치 한 후 OSX에서 사용할 수 있습니다 .coreutils
brew install coreutils
답변
지금까지 최고의 솔루션 인 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
답변
일반적으로 사용 가능한 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
이진 파일을 건너 뛰는 논리는 이 게시물 에서 나온 것 입니다.
노트:
- 이것을하는 것은 자식이나 svn repo에서 위험 할 수 있습니다
- 문자열 리터럴에 탭이 포함 된 코드 파일이있는 경우 올바른 솔루션이 아닙니다.
답변
디렉토리의 모든 파일에서 탭을 공백으로 변환하려면 어떻게해야합니까 (재귀 적으로)?
이것은 일반적으로 원하는 것이 아닙니다 .
png 이미지에 대해이 작업을 수행 하시겠습니까? PDF 파일? .git 디렉토리? 당신의
Makefile
( 필요한 탭 합니까)? 5GB SQL 덤프?
이론적으로는 많은 exlude 옵션을 전달할 수 있습니다. find
당신이 사용하는 다른 . 그러나 이것은 깨지기 쉽고 다른 바이너리 파일을 추가하자마자 깨질 것입니다.
당신이 원하는 것은 최소한 :
- 특정 크기 이상의 파일을 건너 뜁니다.
- NULL 바이트가 있는지 확인하여 파일이 이진인지 감지합니다.
- 파일 의 시작 부분 에서만 탭을 교체 하십시오 (
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)