파일의 한 줄 주위에 내용을 추가하는 POSIX 방법

파일의 한 줄 주위에 내용을 추가하는 POSIX 방법

저는 C에서 변수에 대한 대체 정의를 제공하는 스크립트를 사용하여 파일을 편집하는 방법을 찾고 있습니다. 이 재정의는 제가 스크립트를 작성하고 있는 POSIX 응용 프로그램을 사용하는 컴파일러의 D 플래그에 의해 제어됩니다. 예를 들어 토큰 이름을 nice_var다음과 같이 바꿔야 한다고 가정해 보겠습니다 cool_var.

입력 예:

struct BigThing nice_var;

/* some lines later */

    nice_var->thing = 1;

예상 출력:

/* TODO temporary ifdef to facilitate renaming */
#ifdef RENAME_FEATURE_ENABLED
struct BigThing cool_var;
#else
struct BigThing nice_var;
#endif /* RENAME_FEATURE_ENABLED */

/* some lines later */

/* TODO temporary ifdef to facilitate renaming */
#ifdef RENAME_FEATURE_ENABLED
    cool_var->thing = 1;
#else
    nice_var->thing = 1;
#endif /* RENAME_FEATURE_ENABLED */

문자열이 나타날 때마다 표시된 전처리기 지시문 패턴으로 묶어야 합니다. 이는 연속된 줄에서 사용되는 경우에도 마찬가지입니다.

예, 이를 수행하기 위해 python/perl/javascript 스크립트를 작성할 수 있습니다. 하지만 이러한 종류의 파일 편집을 지원할 수 있는 POSIX 애플리케이션이 있습니까? 나는 이것을 기대 ed하거나 할 수 있지만 파일의 모든 항목을 반복하는 방법이나 검색이 파일 끝에 도달한 시기를 감지하는 방법을 ex모릅니다 . 이를 감지하는 방법에 대한 정보는 목표를 달성하는 데 필요한 전부일 수 있습니다.edexex

확실하지 않은 경우 이 스크립트(이라고 부르겠습니다 renamer)를 사용하여 다음과 같이 "nice_var"가 나타나는 작업 공간의 모든 파일을 편집할 계획입니다.

#!/bin/bash -eux
for file in $(grep --files-with-matches --recursive 'nice_var'); do
    renamer --feature-name RENAME_FEATURE_ENABLED --var-name 'nice_var' --replacement 'cool_var' "${file}"
done

답변에서 명령줄 인수를 처리할 필요가 없습니다. 나는 일치하는 줄 앞에 내용을 추가하고 해당 줄을 복제하는 개념에 더 관심이 있습니다.

질문은 실제로 다음과 같이 요약됩니다. "패턴을 반복적으로 검색한 다음 패턴이 발견된 줄 앞뒤에 줄을 추가하는 기능을 지원하는 POSIX 애플리케이션이 있습니까? 여기서 추가된 줄 중 하나는 패턴과 일치하지만 패턴은 대체됩니다. ?"

어쩌면 awk여러 번 패스할까요?

답변1

이는 텍스트가 변수인지, 주석 줄( /* don't change nice_var here */), 문자열 내의 인용문( char *p = "I've got nice_var here"), 심지어 다른 단어 부분( int quitenice_vartoo) 인지에 관계없이 언어 구문에 대한 지식이 필요하지 않은 간단한 대체를 제공하는 "최선의 노력" 솔루션입니다. . 이를 올바르게 수행하려면 C 파서의 근사치가 필요합니다.

awk -v src=nice_var -v dst=cool_var -v macro=RENAME_FEATURE_ENABLED '
    $0 ~ src {
        this = that = $0;
        gsub(src, dst, that);
        printf "/* TODO temporary ifdef to facilitate renaming */\n#ifdef %s\n%s\n#else\n%s\n#endif /* %s */\n", macro, that, this, macro;
        next
    }
    1
' sourcefile.c

귀하의 예 출력 :

/* TODO temporary ifdef to facilitate renaming */
#ifdef RENAME_FEATURE_ENABLED
struct BigThing cool_var;
#else
struct BigThing nice_var;
#endif /* RENAME_FEATURE_ENABLED */

/* some lines later */

/* TODO temporary ifdef to facilitate renaming */
#ifdef RENAME_FEATURE_ENABLED
    cool_var->thing = 1;
#else
    nice_var->thing = 1;
#endif /* RENAME_FEATURE_ENABLED */

이는 실제로 src대체 텍스트를 일치시키는 데 사용되는 정규식입니다. awk내 예는 문자열 리터럴이지만 반드시 그럴 필요는 없습니다.

답변2

사용 sed:

/nice_var/!b
h
i\
/* TODO temporary ifdef to facilitate renaming */\
#ifdef RENAME_FEATURE_ENABLED
s//cool_var/gp
i\
#else
g
a\
#endif /* RENAME_FEATURE_ENABLED */

일치하지 않는 줄을 무시합니다 nice_var(각 줄에 대해 스크립트 끝으로 분기). 일치하는 라인의 경우 nice_var, 예약된 공간에 라인을 저장하고 h, "접두사"( #ifdef ...)를 삽입하고, 수정된 라인 nice_var으로 변경하여 인쇄하고, "중위"( )를 삽입하고, 예약된 공간에서 원래 라인을 가져옵니다 (이것은 실용적이지 않습니다). 인쇄하지 않고 암시적 인쇄는 끝에 이 작업을 수행합니다. "접미사"( )가 추가됩니다.cool_var#elseg#endif

시험:

$ cat file.c
struct BigThing nice_var;

/* some lines later */

    nice_var->thing = 1;
$ sed -f script file.c
/* TODO temporary ifdef to facilitate renaming */
#ifdef RENAME_FEATURE_ENABLED
struct BigThing cool_var;
#else
struct BigThing nice_var;
#endif /* RENAME_FEATURE_ENABLED */

/* some lines later */

/* TODO temporary ifdef to facilitate renaming */
#ifdef RENAME_FEATURE_ENABLED
    cool_var->thing = 1;
#else
    nice_var->thing = 1;
#endif /* RENAME_FEATURE_ENABLED */

스크립트를 매개변수화하려면 sed여기의 설명서를 사용하세요. 이를 위해서는 첫 번째 인수가 sed대체 패턴으로 사용하기에 적합한 POSIX 기본 정규 표현식이어야 하고, 두 번째 인수가 대체 명령의 대체 부분에 적합한 텍스트 문자열이어야 합니다. 세 번째 인수는 유효한 C 전처리기 매크로 이름이어야 합니다.

src=$1
dst=$2
mac=$3

cat >script <<SED_SCRIPT
/$src/!b
h
i\\
/* TODO temporary ifdef to facilitate renaming */\\
#ifdef $mac
s//$dst/gp
i\\
#else
g
a\\
#endif /* $mac */
SED_SCRIPT

sed -f script

시험:

$ sh replacer nice cool HELLO <file.c
/* TODO temporary ifdef to facilitate renaming */
#ifdef HELLO
struct BigThing cool_var;
#else
struct BigThing nice_var;
#endif /* HELLO */

/* some lines later */

/* TODO temporary ifdef to facilitate renaming */
#ifdef HELLO
    cool_var->thing = 1;
#else
    nice_var->thing = 1;
#endif /* HELLO */
$ sh replacer 'nice_\(var\)' '\1iable' HELLO <file.c
/* TODO temporary ifdef to facilitate renaming */
#ifdef HELLO
struct BigThing variable;
#else
struct BigThing nice_var;
#endif /* HELLO */

/* some lines later */

/* TODO temporary ifdef to facilitate renaming */
#ifdef HELLO
    variable->thing = 1;
#else
    nice_var->thing = 1;
#endif /* HELLO */

관련 정보