一个字符串替换小工具 (2013.12.28 updated)

背景: 我用若干个不同的配置文件大同小异,只是几个参数不同。如果一个个手工去修改,非常繁琐。于是有下面的:

/*in-place replace mth line 's nth word with val,  keeping spaces as original as possible.

not support tab, you may use:
  sed -i 's/\t/    /g' inputfile

usage example:
 find . -name config.mak -exec ./file-inplace {} 260 3 '2#' \;

if on linux, keep PC dos ending:
 find . -name config.mak -exec unix2dos {} \;
 


author: ludi 2013.12
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char line[9192];

int word_len(char *w)
{
	int len = 0;
	
	/*while(!isspace(*w)){++w; ++len;} <-- can't handle non-ascii*/

	for(;*w; ++w){
		if(' ' == *w || '\n' == *w || '\t' == *w){break;}
		++len;
	}

	return len;
}

int work(char *line, int n, char *val)
{
	char *ptr = line;
	int wlen, vlen, s = 0, cnt = 0;

	for(; *ptr; ++ptr)
	{
		if(*ptr!= ' '){
			s = 1;
		}else if(1 == s){
			++cnt;
			s = 0;
		}

		if(cnt == n){
			while(*ptr == ' ')++ptr;
			wlen = word_len(ptr);
			vlen = strlen(val);
			
			if(vlen > wlen){
				if(ptr[vlen] != ' ')memmove(ptr+vlen+1, ptr+wlen+1, strlen(ptr+wlen+1));
				strncpy(ptr, val, vlen);
				ptr[vlen] = ptr[vlen] ? ' ': '\n';
			}else{
				strncpy(ptr, val, vlen);
				ptr += vlen;
				while(*ptr != ' ' && *ptr != '\n' && *ptr != '\t')*ptr++ = ' ';
			}

			break;
		}
	}
}

int main(int ac, char **av)
{
	int mth, nth;
	char *val, *tmpname = "xx.tmp";
	FILE *fp, *tp;
	int i, ch;
	
	if(ac < 5)return printf("usage: file-in-replace inputfile mth nth val\n");
	
	fp = fopen(av[1], "r+");
	tp = fopen(tmpname, "w+");
	if(!fp||!tp){return printf("can't open %s", av[1]);}

	mth = atoi(av[2]);
	nth = atoi(av[3]);
	val = av[4];
	
	for(i = 1; ; ++i){
		memset(line, 0, sizeof(line));
		if(!fgets(line, sizeof(line), fp)){break;}
		if(i == mth){
			work(line, nth-1, val);
		}
		fprintf(tp, "%s", line);
	}

	rewind(fp);
	rewind(tp);

	/*while(!feof(tp))fputc(fgetc(tp), fp);*/
	while((ch = fgetc(tp)) != EOF){
		fputc(ch, fp);
	}
	

	fclose(fp);
	fclose(tp);
	remove(tmpname);

	return 0;
}


 

 最先我也尝试过gawk, sed, 发现gawk 不能保留空格,这影响源文件的对齐。于是抽象了一个line-in-replace, 用这样的方案:

 FILE=def.txt NR=160 COL=2 VAL=259
 TMP=$(head -n $NR  $FILE  | tail -n 1 | ./line-in-replace $COL $VAL)
 LANG=C sed -i -e "$NR s/.*/$TMP/" $FILE

那个LANG是为了处理中文,必须有,不然sed不正常。

后来觉得这三行复制粘贴也太麻烦,于是就整出了上面的file-in-replace。

贴在这里是为了记录我遇到的问题,一遍以后查。

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值