免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 5528 | 回复: 20
打印 上一主题 下一主题

[文本处理] 文本替换求助 [复制链接]

论坛徽章:
18
辰龙
日期:2014-05-21 21:01:4115-16赛季CBA联赛之深圳
日期:2016-12-23 13:51:3815-16赛季CBA联赛之北控
日期:2016-11-28 18:26:3815-16赛季CBA联赛之佛山
日期:2016-11-03 11:18:5815-16赛季CBA联赛之辽宁
日期:2016-07-10 16:09:4115-16赛季CBA联赛之江苏
日期:2016-02-20 23:09:202015亚冠之塔什干棉农
日期:2015-08-17 19:49:492015年亚洲杯之日本
日期:2015-04-30 01:24:342015年亚洲杯之约旦
日期:2015-04-01 00:37:182015年亚洲杯之沙特阿拉伯
日期:2015-03-02 15:55:40处女座
日期:2014-05-25 10:34:0020周年集字徽章-年
日期:2023-04-23 11:17:52
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-12-28 12:07 |只看该作者 |倒序浏览
30可用积分
本帖最后由 bikkuri 于 2015-12-28 12:32 编辑

大家好!
我有一个问题向大家请教。
假如有以下两个文件main.sh和new.def
# main.sh
#
#-----------------------DEFINITIONS-----------------------------
host1=www.baidu.com
host2=www.sina.com.cn
host3=www.netease.com
#-----------------------DEFINITIONS-----------------------------
for i in $(seq 3); do
[ ! "A"$(eval echo '$'host$i) = "A" ] && echo "host$i is $(eval echo '$'host$i)"
done


# new.def
#-----------------------DEFINITIONS-----------------------------
host1=www.google.com
host2=www.yahoo.com.cn
#-----------------------DEFINITIONS-----------------------------

希望用new.def中两条分割线中间的内容(行数不确定)来替换掉main.sh中两条分割线中间的内容(行数不确定)。
改变后新的main.sh的内容应该变成:
# main.sh
#
#-----------------------DEFINITIONS-----------------------------
host1=www.google.com
host2=www.yahoo.com.cn
#-----------------------DEFINITIONS-----------------------------
for i in $(seq 3); do
[ ! "A"$(eval echo '$'host$i) = "A" ] && echo "host$i is $(eval echo '$'host$i)"
done

谢谢大家!

论坛徽章:
54
2015亚冠之德黑兰石油
日期:2015-07-07 13:00:1615-16赛季CBA联赛之深圳
日期:2016-03-31 09:03:5415-16赛季CBA联赛之辽宁
日期:2016-05-09 20:38:15程序设计版块每日发帖之星
日期:2016-05-12 06:20:0015-16赛季CBA联赛之四川
日期:2016-05-13 15:19:4715-16赛季CBA联赛之福建
日期:2016-05-15 20:24:34每日论坛发贴之星
日期:2016-05-16 06:20:0015-16赛季CBA联赛之吉林
日期:2016-05-26 11:49:4715-16赛季CBA联赛之广东
日期:2016-05-26 13:49:18极客徽章
日期:2016-12-07 14:05:2315-16赛季CBA联赛之广夏
日期:2016-12-20 17:33:532017金鸡报晓
日期:2017-01-10 15:19:56
2 [报告]
发表于 2015-12-28 12:07 |只看该作者
本帖最后由 haooooaaa 于 2015-12-28 13:52 编辑
  1. awk -vRS='#--*DEFINITIONS--*\n' 'NR==FNR{if(FNR==2)s=$0;next}{printf "%s",FNR==2?RT s RT:$0}' new.def main.sh
  2. # main.sh
  3. #
  4. #-----------------------DEFINITIONS-----------------------------
  5. host1=www.google.com
  6. host2=www.yahoo.com.cn
  7. #-----------------------DEFINITIONS-----------------------------
  8. for i in $(seq 3); do
  9. [ ! "A"$(eval echo 'host$i) = "A" ] && echo "host$i is $(eval echo 'host$i)"
  10. done
复制代码
  1. awk -F= -vOFS='=' 'NR==FNR{if(/^host/)a[++c]=$2;next}{if(/^host/)if(c){$2=a[c--]}else{next}}1' new.def main.sh
复制代码

论坛徽章:
145
技术图书徽章
日期:2013-10-01 15:32:13戌狗
日期:2013-10-25 13:31:35金牛座
日期:2013-11-04 16:22:07子鼠
日期:2013-11-18 18:48:57白羊座
日期:2013-11-29 10:09:11狮子座
日期:2013-12-12 09:57:42白羊座
日期:2013-12-24 16:24:46辰龙
日期:2014-01-08 15:26:12技术图书徽章
日期:2014-01-17 13:24:40巳蛇
日期:2014-02-18 14:32:59未羊
日期:2014-02-20 14:12:13白羊座
日期:2014-02-26 12:06:59
3 [报告]
发表于 2015-12-28 12:29 |只看该作者
分成main.def跟main.src
main.sh = main.def + main.src

论坛徽章:
18
辰龙
日期:2014-05-21 21:01:4115-16赛季CBA联赛之深圳
日期:2016-12-23 13:51:3815-16赛季CBA联赛之北控
日期:2016-11-28 18:26:3815-16赛季CBA联赛之佛山
日期:2016-11-03 11:18:5815-16赛季CBA联赛之辽宁
日期:2016-07-10 16:09:4115-16赛季CBA联赛之江苏
日期:2016-02-20 23:09:202015亚冠之塔什干棉农
日期:2015-08-17 19:49:492015年亚洲杯之日本
日期:2015-04-30 01:24:342015年亚洲杯之约旦
日期:2015-04-01 00:37:182015年亚洲杯之沙特阿拉伯
日期:2015-03-02 15:55:40处女座
日期:2014-05-25 10:34:0020周年集字徽章-年
日期:2023-04-23 11:17:52
4 [报告]
发表于 2015-12-28 12:36 |只看该作者
本帖最后由 bikkuri 于 2015-12-28 12:56 编辑

不能分的。
平时就是一个main.sh。
只在偶尔的情况下要修改definition。
这种情况下main.sh如果发现new.def文件的存在就把其内容读取替换main.sh中的内容。
也就是说new.def只是一个临时文件,其内容被读取以后就没用了,会被删除。

[root@nchip:/tmp/test]# grep -n DEF new.def
2:#-----------------------DEFINITIONS-----------------------------
5:#-----------------------DEFINITIONS-----------------------------
[root@nchip:/tmp/test]# grep -n DEF main.sh
3:#-----------------------DEFINITIONS-----------------------------
7:#-----------------------DEFINITIONS-----------------------------
[root@nchip:/tmp/test]#

能不能用grep命令得到要替换内容的范围,然后用sed -i来修改main.sh文件。
例如上面例子,用new.def的第2-5行替换main.sh的第3-7行。

回复 2# jason680


   

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
5 [报告]
发表于 2015-12-28 13:16 |只看该作者
回复 3# bikkuri


    写个小脚本嘛:

#!/usr/bin/perl

use strict;
use warnings;

use v5.14;
use autodie;

if (@ARGV != 2) {
    die "Usage: $0 new.def main.sh";
}

my $replacements = load_replacement($ARGV[0]);

replace_and_print($replacements, $ARGV[1]);

sub load_replacement {
    local @ARGV = @_;

    my %replacements;
    my $separator = qr/^#-+(\w+)-+$/;
    my $keyword;

    while (<>) {
        if (/$separator/ ... /$separator/) {
            if (not $keyword) {
                $keyword = $1;
                push @{$replacements{$keyword}}, $_;
            } else {
                push @{$replacements{$keyword}}, $_;
                if (/$separator/) {
                    if ($keyword ne $1) {
                        die "Invalid file format: expect keyword $keyword, got $1";
                    }
                    $keyword = undef;
                }
            }
        }
    }

    wantarray ? %replacements : \%replacements;
}

sub replace_and_print {
    my $replacements = shift @_;
    local @ARGV = @_;

    my $separator = qr/^#-+(\w+)-+$/;
    my ($keyword, $in_replacement);
    while (<>) {
        if (/$separator/) {
            if (not $in_replacement) {
                $keyword = $1;
                if (exists $replacements->{$keyword}) {
                    $in_replacement = 1;
                }
            } else {
                print for @{$replacements->{$keyword}};
                $keyword = $in_replacement = undef;
            }
        } else {
            print unless $in_replacement;
        }
    }

    if ($in_replacement) {
        print for @{$replacements->{$keyword}};
    }
}

论坛徽章:
84
每日论坛发贴之星
日期:2015-12-29 06:20:00每日论坛发贴之星
日期:2016-01-16 06:20:00每周论坛发贴之星
日期:2016-01-17 22:22:00程序设计版块每日发帖之星
日期:2016-01-20 06:20:00每日论坛发贴之星
日期:2016-01-20 06:20:00程序设计版块每日发帖之星
日期:2016-01-21 06:20:00每日论坛发贴之星
日期:2016-01-21 06:20:00程序设计版块每日发帖之星
日期:2016-01-23 06:20:00程序设计版块每日发帖之星
日期:2016-01-31 06:20:00数据库技术版块每日发帖之星
日期:2016-01-16 06:20:00程序设计版块每日发帖之星
日期:2016-01-16 06:20:00程序设计版块每日发帖之星
日期:2016-01-14 06:20:00
6 [报告]
发表于 2015-12-28 13:27 |只看该作者
这个办法比较笨:

[yjh@host tmp]$ awk 'BEGIN{RS="#-----------------------DEFINITIONS-----------------------------"} NR==1 {print $0}' kkk.txt >main.sh.new
echo "#-----------------------DEFINITIONS-----------------------------" >>main.sh.new
[yjh@host tmp]$ awk 'BEGIN{RS="#-----------------------DEFINITIONS-----------------------------"} NR==2 {print $0}' new.txt >>main.sh.new
echo "#-----------------------DEFINITIONS-----------------------------" >>main.sh.new
[yjh@host tmp]$ awk 'BEGIN{RS="#-----------------------DEFINITIONS-----------------------------"} NR==3 {print $0}' kkk.txt >>main.sh.new
  1. [yjh@host tmp]$ cat kkk.txt
  2. # main.sh
  3. #
  4. #-----------------------DEFINITIONS-----------------------------
  5. host1=www.baidu.com
  6. host2=www.sina.com.cn
  7. host3=www.netease.com
  8. #-----------------------DEFINITIONS-----------------------------
  9. for i in $(seq 3); do
  10. [ ! "A"$(eval echo 'host$i) = "A" ] && echo "host$i is $(eval echo 'host$i)"
  11. done
  12. [yjh@host tmp]$ cat new.txt
  13. # new.def
  14. #-----------------------DEFINITIONS-----------------------------
  15. host1=www.google.com
  16. host2=www.yahoo.com.cn
  17. #-----------------------DEFINITIONS-----------------------------
复制代码

论坛徽章:
20
卯兔
日期:2015-01-26 22:05:142015亚冠之萨济拖拉机
日期:2015-09-10 15:15:282015亚冠之阿尔希拉尔
日期:2015-09-25 17:37:53程序设计版块每日发帖之星
日期:2015-10-03 06:20:00程序设计版块每日发帖之星
日期:2015-12-09 06:20:00CU十四周年纪念徽章
日期:2015-12-17 09:07:15程序设计版块每日发帖之星
日期:2015-12-25 06:20:34程序设计版块每日发帖之星
日期:2015-12-25 06:20:34程序设计版块每日发帖之星
日期:2015-12-25 06:20:342015亚冠之广州富力
日期:2015-08-27 19:29:56每日论坛发贴之星
日期:2015-08-26 06:20:002015亚冠之阿尔希拉尔
日期:2015-05-18 17:26:27
7 [报告]
发表于 2015-12-28 13:35 |只看该作者
回复 1# bikkuri
  1. awk 'FNR==NR{if($0~/^#-+/&&!f){f=1;next}if($0~/^#-+/&&f){f=0}if(f){s=s?s"\n"$0:$0}next}/^#-+/&&!x{x=1;print;next}/^#-+/&&x{x=0;print s}x{next}1' new.def main.sh
  2. # main.sh
  3. #
  4. #-----------------------DEFINITIONS-----------------------------
  5. host1=www.google.com
  6. host2=www.yahoo.com.cn
  7. #-----------------------DEFINITIONS-----------------------------
  8. for i in $(seq 3); do
  9. [ ! "A"$(eval echo 'host$i) = "A" ] && echo "host$i is $(eval echo 'host$i)"
  10. done
复制代码

论坛徽章:
16
CU十二周年纪念徽章
日期:2013-10-24 15:41:3415-16赛季CBA联赛之广东
日期:2015-12-23 21:21:55青铜圣斗士
日期:2015-12-05 10:35:30黄金圣斗士
日期:2015-11-26 20:42:16神斗士
日期:2015-11-19 12:47:50每日论坛发贴之星
日期:2015-11-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-18 06:20:002015亚冠之城南
日期:2015-11-10 19:10:492015亚冠之萨济拖拉机
日期:2015-10-28 18:47:282015亚冠之柏太阳神
日期:2015-08-30 17:21:492015亚冠之山东鲁能
日期:2015-07-07 18:48:39摩羯座
日期:2014-08-29 23:01:42
8 [报告]
发表于 2015-12-28 13:56 |只看该作者
awk 'BEGIN{i=0;j=0}NR==FNR{a[i++]=$0;next}/DEFINITIONS/&&!mild{if(!mild){mild=1;print $0;next}}/DEFINITIONS/&&mild{while (j<(i-1))print a[++j];mild=0}mild{if (j < (i-2))$0=a[++j]; else {j++;next}}1' b.txt a.txt

论坛徽章:
18
辰龙
日期:2014-05-21 21:01:4115-16赛季CBA联赛之深圳
日期:2016-12-23 13:51:3815-16赛季CBA联赛之北控
日期:2016-11-28 18:26:3815-16赛季CBA联赛之佛山
日期:2016-11-03 11:18:5815-16赛季CBA联赛之辽宁
日期:2016-07-10 16:09:4115-16赛季CBA联赛之江苏
日期:2016-02-20 23:09:202015亚冠之塔什干棉农
日期:2015-08-17 19:49:492015年亚洲杯之日本
日期:2015-04-30 01:24:342015年亚洲杯之约旦
日期:2015-04-01 00:37:182015年亚洲杯之沙特阿拉伯
日期:2015-03-02 15:55:40处女座
日期:2014-05-25 10:34:0020周年集字徽章-年
日期:2023-04-23 11:17:52
9 [报告]
发表于 2015-12-28 14:01 |只看该作者
本帖最后由 bikkuri 于 2015-12-28 14:01 编辑

谢谢您的帮助!
您的命令正是我想要的。
但是在处理实际脚本的时候发现出错了。
例如将刚才的main.sh换成以下内容。
  1. # main.sh
  2. #
  3. #-----------------------DEFINITIONS-----------------------------
  4. host1=www.baidu.com
  5. host2=www.sina.com.cn
  6. host3=www.netease.com
  7. #-----------------------DEFINITIONS-----------------------------
  8. base64_decode()
  9. {
  10. if [ -f /usr/bin/uudecode ] ; then
  11. echo "begin-base64 644 b" > $dec64
  12. awk '{print $0}' >> $dec64
  13. echo "====" >> $dec64
  14. uudecode -o $out64 $dec64
  15. cat $out64
  16. rm -f $dec64 $out64
  17. else
  18. local buff=""
  19. for buff in $(awk -v B64="$CODE" '{while(length()){split(substr($0,1,4),a,"");$0=substr($0,5);t=0;for(i=3;i>=0;i--){z=1;for(p=0;p<6*i;p++)z=z*2;t=t+z*((a[4-i]=="=")?0:index(B64,a[4-i])-1)}for(i=2;i>=0;i--)if(a[4-i]!="="){y=1;for(p=0;p<8*i;p++)y=y*2;printf("\\x%x",t/y);t%=y}}printf"\n"}');do printf "$buff"; done
  20. fi
  21. }
复制代码
然后再执行您的命令就会报错:
  1. [root@nchip:/tmp/test]# awk -vRS='#--*DEFINITIONS--*\n' 'NR==FNR{if(FNR==2)s=$0;next}{printf FNR==2?RT s RT:$0;}' new.def main.sh
  2. # main.sh
  3. #
  4. #-----------------------DEFINITIONS-----------------------------
  5. host1=www.google.com
  6. host2=www.yahoo.com.cn
  7. #-----------------------DEFINITIONS-----------------------------
  8. awk: cmd. line:1: Invalid format specifier
  9. [root@nchip:/tmp/test]#
复制代码
如果把那行最长的for开头的行去掉,执行就不会报错。
为什么会有这种情况发生呢?
谢谢!

回复 5# haooooaaa


   

论坛徽章:
54
2015亚冠之德黑兰石油
日期:2015-07-07 13:00:1615-16赛季CBA联赛之深圳
日期:2016-03-31 09:03:5415-16赛季CBA联赛之辽宁
日期:2016-05-09 20:38:15程序设计版块每日发帖之星
日期:2016-05-12 06:20:0015-16赛季CBA联赛之四川
日期:2016-05-13 15:19:4715-16赛季CBA联赛之福建
日期:2016-05-15 20:24:34每日论坛发贴之星
日期:2016-05-16 06:20:0015-16赛季CBA联赛之吉林
日期:2016-05-26 11:49:4715-16赛季CBA联赛之广东
日期:2016-05-26 13:49:18极客徽章
日期:2016-12-07 14:05:2315-16赛季CBA联赛之广夏
日期:2016-12-20 17:33:532017金鸡报晓
日期:2017-01-10 15:19:56
10 [报告]
发表于 2015-12-28 14:03 |只看该作者
回复 9# bikkuri


    因为里面的 printf , 如果有百分号可能有问题, 已更改, 请看上面的相关内容
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP