我在我的输入代码一对夫妇的结构定义。 例如:
struct node {
int val;
struct node *next;
};
要么
typedef struct {
int numer;
int denom;
} Rational;
我用下面的线将它们转换成一行,并复制它两次。
sed '/struct[^(){]*{/{:l N;s/\n//;/}[^}]*;/!t l;s/ */ /g;p;p}'
结果是这样的:
struct node { int val; struct node *next;};
struct node { int val; struct node *next;};
struct node { int val; struct node *next;};
typedef struct { int numer; int denom;} Rational;
typedef struct { int numer; int denom;} Rational;
typedef struct { int numer; int denom;} Rational;
这就是我要的:
- 我想的第一行被恢复到原来的结构块
我想第二行变成一个功能标题看起来像这样...
void init_structName( structName *var, int data1, int data2 )
-structName基本结构的名称。
-var是你喜欢的任何名称。
-data1,数据2 ....是是在结构中的值。
3.我想第三行变成以函数体。 我在哪里初始化的数据参数。 它是这样的。
{
var->data1 = data1;
var->data2 = data2;
}
请记住,在输入文件中的所有我的结构定义放置在一个行,抄三次。 因此,当代码发现的结构确定指标可以假定会有以下两个副本。
例如,这是我想如果输入文件具有上面所示的重复的线的输出。
struct node {
int val;
struct node *next;
};
void init_node(struct node *var, int val, struct node *next)
{
var->val = val;
var->next = next;
}
typedef struct {
int numer;
int denom;
} Rational;
void init_Rational( Rational *var, int numer, int denom )
{
var->numer = numer;
var->denom = denom;
}
万一有人很好奇。 这些功能将在主函数中调用初始化结构变量。
有人能帮忙吗? 我意识到这是一种艰难的。 非常感谢!!
眼看sed的是图灵完备 ,可以做到在一个单一的去,但是,这并不意味着该代码是非常用户友好=)
我的一个解决方案,企图将是:
#!/bin/sed -nf
/struct/b continue
p
d
: continue
# 1st step:
s/\(struct\s.*{\)\([^}]*\)\(}.*\)/\1\
\2\
\3/
s/;\(\s*[^\n}]\)/;\
\1/g
p
s/.*//
n
# 2nd step:
s/struct\s*\([A-Za-z_][A-Za-z_0-9]*\)\s*{\([^}]*\)}.*/void init_\1(struct \1 *var, \2)/
s/typedef\s*struct\s*{\([^}]*\)}\s*\([A-Za-z_][A-Za-z_0-9]*\)\s*;/void init_\2(struct \2 *var, \1)/
s/;/,/g
s/,\s*)/)/
p
s/.*//
n
# 3rd step
s/.*{\s*\([^}]*\)}.*/{\
\1}/
s/[A-Za-z \t]*[\* \t]\s*\([A-Za-z_][A-Za-z_0-9]*\)\s*;/\tvar->\1 = \1;\
/g
p
我会尽力解释一切,我做到了,但首先我必须警告说,这可能还不是很普遍。 例如,它假定三个相同线彼此跟随(即,它们之间没有其他的线)。
在开始之前,请注意,该文件是要求“-n”标志运行的脚本。 这告诉sed不打印任何东西到标准输出,除非剧本明确它告诉给(通过“p”命令,例如)。 在“-f”选项是一个“绝招”告诉sed来打开后面的文件。 当“./myscript.sed”执行脚本,bash将执行‘/ bin中/ SED -nf myscript.sed’,所以它会正确地读剧本的其余部分。
步骤零将只是一个检查,看看,如果我们有一个有效的线。 我假设每一个有效行包含字结构。 如果该行是有效的,脚本分支(跳跃,在“B”命令等同于C中的goto语句)将继续标签(不同于C,标签开始“:”,而不是与它在结束)。 如果它不是有效的,我们迫使它与所述“p”命令被印刷,然后删除从图案空间中的线与“d”的命令。 通过删除线,SED将读取下一行并从头开始执行脚本。
如果该行是有效的,行动改变行开始。 第一步骤是生成该结构体。 这是通过一系列命令来完成。
- 分开线分成三个部分,一切到开口支架,一切到右括号(但不包括它),以及一切从关闭托架(现在包括它)。 我要指出的sed的怪癖之一是我们搜索为“\ n”换行,但有一个“\”后跟实际换行写换行符。 这就是为什么这个命令被分成三个不同的线路。 IIRC这种行为是特定于POSIX sed的,但可能是GNU版本(目前在大多数Linux发行版),允许写为“\ n”一个换行符。
- 每个分号后面添加一个换行符。 该这部作品是一个有点尴尬,我们分号之后插入新行后的分号后复制的一切。 G标志告诉sed反复这样做,这就是为什么它的工作原理。 再次还要注意换行符逃逸。
- 强制结果将被打印
在第二步骤之前,我们手动清除从该图案空间(即缓存器)的线,因此,我们可以开始新鲜下一行。 如果我们这样做的“d”命令,sed的将开始从文件的开头再次读取命令。 “n”个命令,然后读取下一行到图案空间。 在那之后,我们开始的命令行转变为一个函数的声明:
- 我们首先匹配字结构,接着是零个或更多的白色空间,然后是C标识符可以与下划线或字母开始,并且可以包含下划线和字母数字字符。 所述标识符被捕获到“可变”“\ 1”。 然后,我们匹配括号内的内容,并保存在“\ 2”。 然后,这些用来生成函数声明。
- 然后,我们做同样的过程,但现在对于“类型定义”的情况。 注意,现在标识符是括号之后,所以“\ 1”现在包含括号内的内容和“\ 2”包含标识符。
- 现在,我们用逗号替换所有分号,所以它可以开始寻找更象一个函数的定义。
- 最后替换命令删除右括号之前额外的逗号。
- 最后打印出结果。
再次,最后一步之前,手动清洁图案空间和读取下一行。 然后一步将生成函数体:
- 匹配和捕获的括号内的一切。 请注意“ *”的开括号之前和之后的右括号。 这是用来因此只有括号中的内容被写入之后。 当写输出,我们放在单独的行打开支架。
- 我们匹配字母字符和空格,这样我们就可以跳过类型声明。 我们需要至少一个空白字符或星号(用于指针)来标记该标识符的开始。 然后我们继续捕捉标识。 这不仅是因为接下来的拍摄工作:我们明确要求,标识后,只有可选的空格之后分号。 这迫使表达分号之前得到的标识字符,即。 如果有两个以上的词,它只会得到最后一个字。 因此,将与“无符号整型VAR”工作,拍摄“变种”正确。 当写输出,我们把一些缺口,随后需要的格式,包括逃脱换行符。
- 打印最终输出。
我不知道如果我是不够清楚。 随意问任何澄清。
希望这有助于=)
这应该给你如何不恰当的实际sed的是这类任务的一些技巧。 我无法弄清楚如何做到这一点的一个传球和我写完剧本的时候,我注意到你期待有所不同的结果。
你的问题是更适合的脚本语言和解析库。 考虑蟒蛇+ pyparsing( 这里有一个例子C结构解析语法,但你需要的东西比这更简单)或perl6的规则 。
不过,这也许会有些用的,如果你决定要坚持用sed:
pass-one.sh
#!/bin/sed -nf
/^struct/ {
s|^\(struct[^(){]*{\)|\1\n|
s|[^}];|;\n|gp
a \\n
}
/^typedef/ {
h
# create signature
s|.*{\(.*\)} \(.*\);|void init_\2( \2 *var, \1 ) {|
# insert argument list to signature and remove trailing ;
s|\([^;]*\); ) {|\1 ) {|g
s|;|,|g
p
g
# add constructor (further substitutions follow in pass-two)
s|.*{\(.*\)}.*|\1|
s|;|;\n|g
s|\n$||p
a }
a \\n
}
pass-two.sh
#!/bin/sed -f
# fix struct indent
/^struct/ {
:loop1
n
s|^ | |
t loop1
}
# unsigned int name -> var->name = name
/^void init_/{
:loop2
n
s|.* \(.*\);| var->\1 = \1;|
t loop2
}
Usage
$ cat << EOF | ./pass-one.sh | ./pass-two.sh
struct node { int val; struct node *next;};
typedef struct { int numer; int denom;} Rational;
struct node { int val; struct node *next;};
typedef struct { int numer; unsigned int denom;} Rational;
EOF
struct node {
int va;
struct node *nex;
};
void init_Rational( Rational *var, int numer, int denom ) {
var->numer = numer;
var->denom = denom;
}
struct node {
int va;
struct node *nex;
};
void init_Rational( Rational *var, int numer, unsigned int denom ) {
var->numer = numer;
var->denom = denom;
}