재귀 디렉터리 계층의 모든 파일에서 후행 공백을 제거하고 싶습니다. 나는 이것을 사용한다 :
find * -type f -exec sed 's/[ \t]*$//' -i {} \;
이 방법은 효과적이지만 발견 된 바이너리 파일에서 후행 "공백"을 제거하므로 바람직하지 않습니다.
어떻게 알 수 있습니까? find
바이너리 파일에서이 명령을 실행하지 않으려면?
file
데이터를 검사 할 수 있습니다.
재귀 디렉터리 계층의 모든 파일에서 후행 공백을 제거하고 싶습니다. 나는 이것을 사용한다 :
find * -type f -exec sed 's/[ \t]*$//' -i {} \;
이 방법은 효과적이지만 발견 된 바이너리 파일에서 후행 "공백"을 제거하므로 바람직하지 않습니다.
어떻게 알 수 있습니까? find
바이너리 파일에서이 명령을 실행하지 않으려면?
file
데이터를 검사 할 수 있습니다.
답변:
당신은 유닉스를 사용할 수 있습니다. file
명령을 사용하면 원하지 않는 파일을 식별하는 데 도움이 될 수 있지만 필자가 원하지 않는 파일 대신 히트 할 파일을 명시 적으로 지정하면 더 좋을 것이라고 생각합니다.
find * -type f \( -name \*.java -o -name \*.c -o -name \*.sql \) -exec sed 's/[ \t]*$//' -i {} \;
소스 제어 파일로 이동하는 것을 피하기 위해 다음과 같은 것을 원할 수 있습니다.
find * \! \( -name .svn -prune \) -type f \( -name \*.java -o -name \*.c -o -name \*.sql \) -exec sed 's/[ \t]*$//' -i {} \;
쉘에 따라 백 슬래시가 필요할 수도 있고 없을 수도 있습니다.
-i
~에 대한 옵션 sed . 이식성있는 쉘 명령을 작성하는 것은 어렵습니다. 그렇지 않습니까?
가장 간단하고 가장 이식 가능한 대답은 이것을 실행하는 것입니다.
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
my @dirs = (@ARGV == 0) ? <*> : @ARGV;
find sub {
next unless -f && -T;
system('perl', '-i', '-pe', 's/[\t\xA0 ]+$//', $File::Find::name);
} => @dirs;
내가 왜 아래 명령을 사용 하는지를 보여주는 이유와 ISO-8859-1 (Latin-1)과 UTF-8 같은 trans-ASCII 텍스트 파일을 다루는 방법도 설명합니다. -ASCII 공백
문제는 발견 (1)은 -T
filetest 연산자를 사용하거나 UTF-8, 사실상 표준 유니 코드 인코딩을 감지해야하는 경우에는 인코딩을 인식하지 않습니다.
바이너리 파일을 버리는 레이어를 통해 파일 이름 목록을 실행하면됩니다. 예를 들어
$ find . -type f | perl -nle 'print if -T' | xargs sed -i 's/[ \t]*$//'
그러나 이제는 파일 이름에 공백 문자를 사용하는 데 어려움이 있으므로 null 종료를 사용하여 늦게해야합니다.
$ find . -type f -print0 | perl -0 -nle 'print if -T' | xargs -0 sed -i 's/[ \t]*$//'
당신이 할 수있는 또 다른 일은 사용하지 않는 것입니다. find
그러나 find2perl
Perl이 이해하고 있기 때문에 -T
이미:
$ find2perl * -type T -exec sed 's/[ \t]*$//' -i {} \; | perl
Perl이 UTF-8 형식의 파일을 사용한다고 가정하려면
$ find2perl * -type T -exec sed 's/[ \t]*$//' -i {} \; | perl -CSD
또는 결과 스크립트를 파일에 저장하고 편집 할 수 있습니다. 당신은 정말로 정말로 -T
이전 파일에 대한 파일 테스트가 아닌 일반 파일 인 경우에만 -f
. 그렇지 않으면 장치 스페셜을 열거 나 FIFO를 차단하는 위험이 있습니다.
그러나, 당신이 모든 것을 할 예정이라면, 당신은 건너 뛸지도 모른다. sed (1) 모두. 한 가지로 POSIX 버전의 sed (1) 이해할 수 없다. -i
반면 Perl의 모든 버전은 그렇습니다. 다음날 sed 사랑스럽게 매우 유용하게 충당 -i
tl이 처음 나타나는 Perl의 옵션.
이것은 또한 정규 표현식을 고칠 수있는 기회를 제공합니다. 실제로 0이 아닌 하나 이상의 후행 가로 공백과 일치하는 패턴을 사용해야합니다. 그렇지 않으면 불필요한 복사로 인해 더 느리게 실행됩니다. 즉, 이것은 :
s/[ \t]*$//
해야한다
s/[ \t]+$//
그러나, 어떻게 얻을 sed (1) 비 POSIX 확장을 필요로한다는 것을 이해하기 위해, 보통 -R
Solaris 또는 Linux와 같은 System Ⅴ Units의 경우 또는 -E
OpenBSD 나 MacOS 같은 BSD 용. 나는 그것이 AIX 하에서는 불가능하다고 생각한다. 휴대용 쉘 스크립트보다 휴대용 쉘을 작성하는 것이 더 쉽습니다.
그것들은 ASCII의 유일한 수평 공백 문자이지만, ISO-8859-1과 결과적으로 Unicode는 코드 포인트 U + 00A0에서 NO BREAK SPACE를 갖습니다. 이것은 많은 유니 코드 코드에서 발견되는 비 ASCII 문자 중 상위 2 개 중 하나입니다. 그리고 나는 사람들의 정규식 코드를 깨뜨린 것을 최근에 보았습니다.
그럼 왜 이렇게하면 안되니?
$ find * -print0 | perl -0 -nle 'print if -f && -T' | xargs -0 perl -i -pe 's/[\t\xA0 ]+$//'
UTF-8 파일을 처리 할 수있는 경우 -CSD
, Perl v5.10 이상을 실행중인 경우 다음을 사용할 수 있습니다. \h
수평 공백 및 \R
일반적인 줄 바꿈은 다음을 포함합니다. \r
, \n
, \r\n
, \f
, \cK
, \x{2028}
, 및 \x{2029}
:
$ find * -print0 | perl -0 -nle 'print if -f && -T' | xargs -0 perl -CSD -i -pe 's/\h+(?=\R*$)//'
모든 UTF-8 파일에서 줄 바꿈에 관계없이 후행 수평 공백을 제거합니다 (유니 코드 문자 속성 HorizSpace
) 각 줄 끝에 유니 코드 줄 바꿈 (CRLF 콤보 포함) 전에 발생하는 성가신 NO-BREAK SPACE가 포함됩니다.
그것도 훨씬 더 휴대용입니다. sed (1) 버전 만 있기 때문에 버전 펄 (1) 구현,하지만 많은 sed (1).
내가 거기에 남아있는 주요 문제는 발견 (1), 왜냐하면 어떤 진정으로 저항하는 시스템 (당신이 AIX와 솔라리스인지 알기 때문에)은 초 임계적인 -print0
지령. 그것이 당신의 상황이라면, 당신은 단지 File::Find
모듈을 Perl에서 직접 다운로드하고 다른 유닉스 유틸리티를 사용하지 마십시오. 다음은 다른 어떤 것에 의존하지 않는 순수한 Perl 버전의 코드입니다.
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
my @dirs = (@ARGV == 0) ? <*> : @ARGV;
find sub {
next unless -f && -T;
system('perl', '-i', '-pe', 's/[\t\xA0 ]+$//', $File::Find::name);
} => @dirs;
ASCII 또는 ISO-8859-1 텍스트 파일로 실행 중이면 괜찮습니다. 그러나 ASCII 또는 UTF-8 파일로 실행중인 경우에는 -CSD
Perl에 대한 내부 호출의 스위치.
ASCII, ISO-8859-1 및 UTF-8 세 가지 모두를 혼합하여 인코딩 한 경우 다른 문제가 발생할 수 있습니다. : 당신은 파일 단위로 인코딩을 알아 내야 할 것이며, 결코 그것을 추측 할 수있는 좋은 방법은 없습니다.
기록을 위해 유니 코드는 26 가지의 공백 문자를 가지고 있습니다. 당신이 사용할 수있는 그만큼 무협 유용 이것들을 냄새 맡기. 처음 세 개의 가로 공백 문자 만이 거의 보입니다.
$ unichars '\h'
---- U+0009 CHARACTER TABULATION
---- U+0020 SPACE
---- U+00A0 NO-BREAK SPACE
---- U+1680 OGHAM SPACE MARK
---- U+180E MONGOLIAN VOWEL SEPARATOR
---- U+2000 EN QUAD
---- U+2001 EM QUAD
---- U+2002 EN SPACE
---- U+2003 EM SPACE
---- U+2004 THREE-PER-EM SPACE
---- U+2005 FOUR-PER-EM SPACE
---- U+2006 SIX-PER-EM SPACE
---- U+2007 FIGURE SPACE
---- U+2008 PUNCTUATION SPACE
---- U+2009 THIN SPACE
---- U+200A HAIR SPACE
---- U+202F NARROW NO-BREAK SPACE
---- U+205F MEDIUM MATHEMATICAL SPACE
---- U+3000 IDEOGRAPHIC SPACE
$ unichars '\v'
---- U+000A LINE FEED (LF)
---- U+000B LINE TABULATION
---- U+000C FORM FEED (FF)
---- U+000D CARRIAGE RETURN (CR)
---- U+0085 NEXT LINE (NEL)
---- U+2028 LINE SEPARATOR
---- U+2029 PARAGRAPH SEPARATOR
GNU grep은 파일이 바이너리인지 여부를 식별하는 데 매우 유용합니다. Solaris 이외에는 기본적으로 GNU grep과 함께 제공되지 않는 다른 플랫폼이있을 것이라고 확신하지만 Solaris와 마찬가지로 설치가 가능할 것으로 확신합니다.
perl -pi -e 's{[ \t]+$}{}g' `grep -lRIP '[ \t]+$' .`
솔라리스에 있다면, grep
와 /opt/csw/bin/ggrep
.
그만큼 grep
플래그는 다음을 수행합니다. l
일치하는 파일의 파일 이름 만 나열하고, R
재귀 적이다. I
텍스트 파일 만 일치 (바이너리 파일 무시) P
perl 호환 정규식 구문입니다.
perl 부분은 파일의 위치를 수정하여 모든 후행 공백 / 탭을 삭제합니다.
마지막으로, UTF8이 문제라면, tchrist의 답은 내 것이어야합니다. grep
당신은 UTF8 지원으로 구축되었습니다 (보통 패키지 관리자는 그런 종류의 기능을 제공하려고합니다).