폴더 내 하위폴더까지 .c 파일 주석을 몽땅 지우려는데 잘 안되네요

일단 구해둔 건 다음 두가지입니다.

  1. 코드를 지울 수 있는 프로그램
    commentremover commented.c uncommented.c와 같이 사용
  2. 코드를 지울 수 있는 sed 스크립트
    commentremover < commented.c > uncommented.c와 같이 사용

하위폴더까지 php파일의 주석을 지우려면 콘솔에서 다음과 같이 하면 된대서

[code:2mrb2zky]find ./ -name ".php" -execdir sed -i '/^#/d;//*/,///d; /^///d; /^$/d;;/^$/d’ {} +[/code:2mrb2zky]
C언어 주석 지우는 sed 스크립트 파일에서 주석과 공백 줄바꿈을 지운 다음 다음과 같이 눈치껏 해 봤는데요

[code:2mrb2zky]find ./ -name ".c" -execdir sed -i {(‘([^']|[\].)’)|("([^&quot;]|[\].)")|(//[^\n])|(/*([^]|[][^/])*/)} +
find ./ -name ".c" -execdir sed -i '//*/!b:x/*//!{Nbx}s//*.*///’ {} +
[/code:2mrb2zky]
위의 것은 bash: syntax error near unexpected token (' (엔터를 누르면 메시지 하나만 뜸) 밑의 것은 sed: -e expression #1, char 22: 예기치 않은 }’ (엔터를 누르면 메시지가 반복해서 뜸)
이렇게 나오네요
find와 조합해서 쓰려면 sed 코드 안에 {}가 들어가면 안 되는건가요?
sed는 만질 줄 모르는데 어떻게 해야 할 지 모르겠네요.

IRC에서의 요청으로 주석이 들어 있는 원문을 올립니다.
아랫쪽 스크립트의 원문입니다.

[code:37h411zx]#!/bin/sed -f

Simple Sed Program to remove all comments from c program

--------------------------------------------------------------------

This is a free shell script under GNU GPL version 2.0 or above

Copyright (C) 2005 nixCraft project.

Feedback/comment/suggestions : http://cyberciti.biz/fb/

-------------------------------------------------------------------------

This script is part of nixCraft shell script collection (NSSC)

Visit http://bash.cyberciti.biz/ for more information.

-------------------------------------------------------------------------

if no /* get next

//*/!b

here we’ve got an /*, append lines until get the corresponding

*/

:x
/*//!{
N
bx
}

delete /.../

s//*.**///[/code:37h411zx]

윗쪽 스크립트의 원문…은 있었는데 어디갔는지 모르겠네요
대신에 다른 스크립트 하나 올려 봅니다.

[code:37h411zx]#! /bin/sed -nf

Remove C and C++ comments, by Brian Hiles (brian_hiles@rocketmail.com)

Sped up (and bugfixed to some extent) by Paolo Bonzini (bonzini@gnu.org)

Works its way through the line, copying to hold space the text up to the

first special character (/, ", '). The original version went exactly a

character at a time, hence the greater speed of this one. But the concept

and especially the trick of building the line in hold space are entirely

merit of Brian.

:loop

This line is sufficient to remove C++ comments!

/^/// s,.*,

/^$/{
x
p
n
b loop
}
/^"/{
:double
/^$/{
x
p
n
/^"/b break
b double
}

H
x
s,\n(.[^&quot;]).,\1,
x
s,.[^&quot;]*,

/^"/b break
/^\/{
H
x
s,\n(.).*,\1,
x
s/.//
}
b double
}

/^‘/{
:single
/^$/{
x
p
n
/^’/b break
b single
}
H
x
s,\n(.[^']).,\1,
x
s,.[^']*,

/^'/b break
/^\/{
H
x
s,\n(.).*,\1,
x
s/.//
}
b single
}

/^/*/{
s/.//
:ccom
s,^.[^],
/^$/ n
/^*//{
s/..//
b loop
}
b ccom
}

:break
H
x
s,\n(.[^"‘/]).,\1,
x
s/.[^"’/]*//
b loop[/code:37h411zx]

분도님 덕분에 끝마쳤습니다.

[code:1b8kp4sw][20:26] <bundo> 저의 결론 find . -name ".c" -execdir sed -i '/^*.?/d;//*/,/*//d; /^///d; /^$/d;;/^$/d’ {} +[/code:1b8kp4sw]
분도님 멋쟁이^^b

–이 명령어를 썼다가 소스 통째로 날려먹어도 분도님이나 저 중 누구도 책임질 수 없음을 알려드립니다.

[code:1b8kp4sw][20:20] <bundo> 백업 하고 하세요 파일 내용 다 지울수 도 있음 ㅎㅎ[/code:1b8kp4sw]

주석 말고도 여기저기 좀 지워지네요;;
아무래도 한 줄짜리 /**/주석이면 문제가 생기는 것 같네요 :shock:

[code:20zlst2r]내용1
/주석1/
지워져버리는
내용2
/주석2/
내용3
/*
주석3
*/
살아남는
내용4
/주석4/
날아가버리는
내용5[/code:20zlst2r]
스크립트를 거친 뒤

[code:20zlst2r]내용1
내용3
살아남는
내용4[/code:20zlst2r]

#!/usr/bin/perl -w

파일명 rmcm.pl

$/ = undef;
chomp($f=$ARGV[0]);
open(H, "<$f") ; $_=<H> ; close H;

s! ((['"]) (?: \. | .)? \2) |
/* .
? */ |
// [^\n\r]*
! $1 || ’ ’
!xseg;
open(H, ">$f") ; print H $_ ; close H;
#--------------------------------------------------------------------------------

find ./ -name "*.c" -a -t f -execdir rmcm.pl {} +

혹시 모르니 -t f 옵션으로 파일만 검색(디렉토리해당없음)

스크립트를 파일에 들어있는 채로 어떻게 할 순 없을까 싶어서이래저래 자꾸 시험해 보다가
윗쪽에 원문 올린 두 스크립트 중 긴 걸 commentremovescript에 넣어서
첫 줄을 #! /bin/sed -inf 로 수정한 뒤
find ./ -name "*.c" -execdir sed -i -n -f ‘commentremovescript’ {} +
로 하니까 잘 되는 걸 확인했습니다.
그런데 파일 많은 폴더에서 시험해 보니까 결과 파일이 (파일명).cf로 저장되다가 어디선가 무한루프에 빠져버렸네요=_=(CPU 100% 먹다가 밤새 돌렸는데도 끝이 안남;)
potatochaos님 방법은 지금 시도해 볼게요

[quote="protochaos":3baasluh]#!/usr/bin/perl -w

파일명 rmcm.pl

$/ = undef;
chomp($f=$ARGV[0]);
open(H, "<$f") ; $_=<H> ; close H;

s! ((['"]) (?: \. | .)? \2) |
/* .
? */ |
// [^\n\r]*
! $1 || ’ ’
!xseg;
open(H, ">$f") ; print H $_ ; close H;
#--------------------------------------------------------------------------------

find ./ -name "*.c" -a -t f -execdir rmcm.pl {} +

혹시 모르니 -t f 옵션으로 파일만 검색(디렉토리해당없음)[/quote:3baasluh]
find가 -t 옵션을 못알아먹는데요;;

[size=200:1dej0die][b:1dej0die]켁 Potato라니…[/b:1dej0die][/size:1dej0die] 쩝…
proto입니다. ㅠㅠ

앗 글고 -t가 아니고, -type으로 해야되네요.
자꾸 줄였는 버릇이 쩝…

펄스크립트인데, 백슬래쉬,따옴표등도 다 처리하고 있네요.

무한 루프에 빠진다니 혹시, .(현재디렉토리)가 패스에 들어 있나요?

find ./ -name "*.c" -a -type f -exec sed -i -n -f ‘commentremovescript’ {} ; 라고 한 번 해보세요.

원래 exec와 execdir의 차이는
exec는 찾는 디렉토리에서 이동않고, 절대경로로 넘겨주고,
execdir는 하위디렉토리로 이동해서, 파일명만 넘겨줘요
; 는 전체 출력에서 {}를 치환해주는 것이고요(줄바꿈이있으니 각각 라인별로 실행됨)
+는 {}로 넘어온 결과를 몽땅 합쳐 하나의 명령으로 처리하는건데 execdir에선 각각 라인별로 실행되더라구요

그리고 혹시 전체 출력결과를 대상으로 한다면 결과가 너무 많으면 명령줄이 너무 길어지는 문제가 생길 수 도 있겠네요.
그렇다면…
find ./ -name "*.c" -a -type f | {
while true;
do
read LINE && sed -i -n -f commentremovescript $LINE || break
done;
}
처럼 스크립트로 해서 줄단위로 실행해 보세요.

쩝 또 빼먹었네 ㅎㅎ

[size=200:1y7c1wao]켁 potato라니…/size:1y7c1wao
죄송합니다. 알고 있었는데 잠시 정신이 나간 모양입니다 :shock: :shock: :shock:

감사합니다. 일단 시도해보고 답변드릴게요. 양이 많다 보니 좀 오래 걸려서요.

무한 루프에 빠질때 자세히 봤더니 하드디스크도 안 읽으면서 CPU 점유율만 100% 먹고 있었네요
폴더를 뒤져 봤더니 sedQl3Vwr처럼 sed(쓰레기값?) 이름으로 된 파일이 권한 000으로 생성돼 있었습니다. 내용은 줄바꿈 하나 뿐이고요.
아마도 스크립트의 오류거나 sed의 오류거나 아니면 둘 다거나 그런 모양입니다.

그래서 해당 폴더 내의 .c 파일의 확장자를 모두 다른 걸로 바꿔 놓고 했더니 그 부분은 또 잘 넘어가다가 나중에 또 오류가 생기네요

근데 이상한게 내수용 옵티머스원 커널 세 개 해외용 옵티머스원 커널 세 개
이렇게 안드로이드 커널의 주석을 지우는 중인데
내수용 커널에는 아무 문제가 없는데 해외용 커널에서는 시도할 때 마다 저렇게 파일이 생성되네요.
해외용 커널에 비해 내수용 커널에 주석이 좀 더 삭제되어 있긴 한데
버퍼 오버플로우라도 발생한걸까요? 잘 모르겠네요;;

펄 스크립트는
find ./ -name "*.c" -a -t f [b:t0h6dvm1]-exec ./[/b:t0h6dvm1]rmcm.pl {} +
이렇게 했더니 하위폴더의 내용은 바뀌지 않았습니다.
execdir할 경우 하위 폴더에서 코드가 실행될 때 파일을 찾을 수 없다고 나와서 exec로 쓰고 있습니다.

위의 펄코드는 원래 표준입력에서 읽어서 변환하게 되어 있는 소스인데,
조금만 바꿔서 매개변수로 한파일만처리하게 만들었으니,
exec cmd {} + 문장처럼 여러파일을 하나의 명령줄로 만들어 넘어온 경우는 처리가 안되지요.
하나의 파일만 바뀔걸요? ㅎㅎ

아래의 코드는 아무래도 펄에대해 너무 모르는것같아 문법을 조금 공부한후에 바꾼 코드입니다.

[code:3tm21mu7]
#!/usr/bin/perl -wi

$/ = undef; #입력레코드분리자를 없앰 (디폴트 \n) : 파일내용을 통째로 읽어들임.

while(<>) { #매개변수를 파일로 인식하고 읽어들임

여기서 !는 /대용으로 s명령을 구분함

s! ((['"]) (?: \. | .)? \2) | #인용된내용 : 인용된부호안의 &quot;,'등은 무시됨
/* .
? */ | #C형식주석 : /* ... /
// [^\n\r]
#C++형식의 줄주석 : //...
! $1 || ’ ’ #back-tick(인용부호안의내용)은 유지, 없으면 제거(주석)
!xseg; #확장정규표현, 싱글라인, 치환내용에도표현식사용, 발견될때마다적용

print; #출력, 그러나 -i옵션에의해 해당파일이 변경됨.

}
[/code:3tm21mu7]

요렇게 고쳐 보세요.
그러면 +나 ;나 같은 결과를 얻을 수 있을겁니다.
execdir이나 exec는 디렉토리이동없이 전체경로를 매개변수로 넘기느냐, 아니면 디렉토리이동후 파일명만 매개변수로 넘기느냐의 차이입니다.

드디어 성공했습니다. 별 문제는 없어 보이네요^^
감사합니다 [s:388fkmxt]potato[/s:388fkmxt]protochaos님 :mrgreen:

주석을 삭제하는 sed 스크립트를 만들어 보았습니다.

[code:3hi33j3r]
#!/bin/sed -Enf
:loop
/^///d
s///.*//g
//*/b comment
p
$q
n
b loop

:comment
{
/*//!N
/*// {
/^/*/d
s//*.**///g
n
}
}
b loop
[/code:3hi33j3r]

주석은 잘 삭제되는데… 문제는 따옴표와 백슬래쉬처리에 문제가 있다는 것이죠.
sed로 이런문제 처리할려니 간단하지가 않더군요.
그러고 awk를 사용하려해도 정규표현식에 제한이 있어서…

[b:3hi33j3r]역시나 이런 쪽은 펄이 강력해 보입니다.[/b:3hi33j3r]
정규표현식에서 왠만한것은 다 핥고 넘어갈 수 있죠.
코드도 몇 줄 밖에 안되는데도 더 완벽히 처리되죠 (물론 정규표현식처리라 좀 느릴 수 도 있지만요…)

그런데 위의 펄 코드에서 삭제하는 방법이 공백으로 바꾸는것인데…
이것이 맘에 안든다면 따옴표사이의공백을 없애면 됩니다.