吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 690|回复: 11
收起左侧

[求助] Linux shell如何根据变量列表批量生成文本

[复制链接]
zwlk 发表于 2023-11-11 11:29
请教下,现有两个文本文件,A.txt和B.txt,A文件第一行是变量名,需要按行替换B文件对应的变量名,生成多个文件。用循环和sed,awk之类的能实现吗?
我现在只会每次替换1个变量,有几列数据就得操作几次,想学习下更简便的方法,希望大神多多赐教
A文件内容如下:
aa       bb     cc    dd
101    201    301  401
102    202   302   402
103    203   303   403
104    204   304   404

B文件内容如下:
hi, aa and cc
hf  bb
dd ,and

举几个例子,生成的C1文件:
hi, 101 and 301
hf  201
401 ,and

生成的C2文件:
hi, 102 and 302
hf  202
402 ,and

生成的C3文件:
hi, 103 and 303
hf  203
403 ,and

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| zwlk 发表于 2023-11-11 15:29
自己研究出来了,不知道是不是最简便的。
这贴可以终结了,能够自己删帖吗?
zhanghailiangji 发表于 2023-11-11 19:36
seq的简略用法
seq命令用于产生从某个数到另外一个数之间的所有整数。

例如:列出1到7的数字

  [root@centos7 data]# seq 7 |tr '\n' ' '
  1 2 3 4 5 6 7
1
2
seq同样支持管道传输

选项 :
-f, --format=格式 使用printf 样式的浮点格式
-s, --separator=字符串 使用指定字符串分隔数字(默认使用:\n)
-w, --equal-width 在列前添加0 使得宽度相同

示例 :

列出1到10间隔为2的数字

  [root@CentOS7 data]# seq 1 2 10 |tr '\n' ' '
  1 3 5 7 9
1
2
列出99到101的数字,并同宽显示

  [root@CentOS7 data]# seq -w 99 101
  099
  100
  101
1
2
3
4
列出99到105间隔为2的数字,并添加-f选项

  [root@CentOS7 data]# seq  99 2 105
  99
  101
  103
  105
  
  [root@CentOS7 data]# seq -f"%3g" 99 2 105
   99
  101
  103
  105
1
2
3
4
5
6
7
8
9
10
11
-f :格式替代符

%b 相对应的参数被视为含有要被处理的转义序列之字符串。
%c ASCII字符。显示相对应参数的第一个字符
%d, %i 十进制整数
%e, %E, %f 浮点格式
%g %e或%f转换,看哪一个较短,则删除结尾的零
%G %E或%f转换,看哪一个较短,则删除结尾的零
%o 不带正负号的八进制值
%s 字符串
%u 不带正负号的十进制值
%x 不带正负号的十六进制值,使用a至f表示10至15
%X 不带正负号的十六进制值,使用A至F表示10至15
%% 字面意义的%
1
2
3
4
5
6
7
8
9
10
11
12
seq无法逆向显示数字

例如:显示10到3的数字

  [root@CentOS7 data]# seq 10 3
  [root@CentOS7 data]#
1
2
例如:显示10到3间隔为2的数字

  [root@CentOS7 data]# seq 10 2 3
  [root@CentOS7 data]#
1
2
for简略用法
格式 :

  for 变量名 in 列表;do     
      循环体
  done
1
2
3
示例 :

将一列数字的值 赋给变量 i

  [root@CentOS7 data]# for i in 1 2 3;do echo number=$i;done
  number=1
  number=2
  number=3
1
2
3
4
当赋给变量 i值 数量过多时,可使用花括号{ }

  [root@CentOS7 data]# for i in {1..5};do echo number=$i;done
  number=1
  number=2
  number=3
  number=4
  number=5
1
2
3
4
5
6
将1到6间隔为2的数字的值赋给变量 i

  [root@CentOS7 data]# for i in {1..6..2};do echo number=$i;done
  number=1
  number=3
  number=5
1
2
3
4
应注意花括号{ }的边界不能出现空格,该格式表示为空格前后是两个不同的赋给变量i 的值,无法识别花括号{ }扩展

  [root@CentOS7 data]# for i in {1..6..2 };do echo number=$i;done
  number={1..6..2
  number=}
1
2
3
for也支持循环递减

例如:将10到5间隔为2的数字的值赋给变量 i

  [root@CentOS7 data]# for i in {10..5..-2};do echo number=$i;done
  number=10
  number=8
  number=6
1
2
3
4
for与seq的循环简略组合用法
使用seq将1到9间隔为3的数字的值赋给变量 i

  [root@CentOS7 data]# for i in `seq 1 3 9`;do echo number=$i;done
  number=1
  number=4
  number=7
1
2
3
4
利用for我们还可以实现类似grep的搜索功能

例如: 将/etc/下所有以 .d 结尾的文件名赋给变量 i,以此达到搜寻该目录下所有以.d结尾的文件。数量过多仅做部分展示

  [root@CentOS7 data]# for id in /etc/*.d;do echo $id;done
  /etc/auto.master.d
  /etc/init.d
  .................
  /etc/rc3.d
  /etc/yum.repos.d
1
2
3
4
5
6
当我们需要修改大量文件名的时候,手动修改是非常效率低下的。因此

使用for便可以实现自动、快速、批量的修改文件名

  [root@CentOS7 scripts]# ls
  f1.txt  f2.txt  f3.txt  f4.log  f5.log  f6.log  f7.png  f8.png  f9.png

  [root@CentOS7 scripts]# vim rename_file.sh

  #!/bin/bash
  for file in /data/scripts/*;do      # 将该目录下所有文件名作为赋值给变量file的参数
          file_headname=`echo $file |sed -nr 's#(.*)\..*$#\1#p'`      # 设置环境变量,取出文件名的头部(.之前的部分)
          mv $file ${file_headname}.apk       # 将原文件名修改,头部不变,后缀改为 .apk
          echo $file is rename ${file_headname}.apk           # 打印至终端,告知用户该文件已被修改
  done        # 结束
1
2
3
4
5
6
7
8
9
10
11
    [root@CentOS7 scripts]# chmod +x rename_file.sh     #给脚本添加执行权限
   
    [root@CentOS7 scripts]# mv rename_file.sh ../   #由于脚本与文件在同一目录下,所以需要移走
   
    [root@CentOS7 scripts]# cd ..   #进入上级目录

    [root@CentOS7 data]# ./rename_file.sh   #执行脚本
    /data/scripts/f1.txt is rename /data/scripts/f1.apk
    /data/scripts/f2.txt is rename /data/scripts/f2.apk
    .................................
    /data/scripts/f8.png is rename /data/scripts/f8.apk
    /data/scripts/f9.png is rename /data/scripts/f9.apk

    [root@CentOS7 data]# ls scripts/    查看核实结果
    f1.apk  f2.apk  f3.apk  f4.apk  f5.apk  f6.apk  f7.apk  f8.apk  f9.apk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
利用for还可以做什么呢?
利用for批量创建用户
编辑一个要创建的用户列表的文件

    [root@CentOS7 data]# vim name.txt
    zhanglang
    mayun
    zhaoritian
    mahuateng

    [root@CentOS7 data]# vim batch_user.sh
    #!/bin/bash
    for USER in `cat /data/name.txt`;do        # 将该目录下的每行字符作为赋值给变量 USER的参数
            if id $USER &> /dev/null;then        # 判断赋值的参数是否为已存在的用户
    echo "$USER is exist.";exit        # 若已存在该用户,则打印至终端,告知用户
            else         # 反之
    useradd $USER        # 创建该用户
    echo $USER | passwd --stdin $USER &> /dev/null        # 将该用户名作为该用户的登录密钥,且登录后立即过期必须修改密钥
    echo "$USER is created."        # 打印至终端,告知用户该用户已创建成功
            fi
    done

    [root@CentOS7 data]# vim batch_user.sh
   
    [root@CentOS7 data]# chmod +x batch_user.sh
   
    [root@CentOS7 data]# ./batch_user.sh
    zhanglang is created.
    mayun is created.
    zhaoritian is created.
    mahuateng is created.
   
    [root@CentOS7 data]# cat /etc/passwd
    ..............................
    zhanglang:x:1002:1002::/home/zhanglang:/bin/bash
    mayun:x:1003:1003::/home/mayun:/bin/bash
    zhaoritian:x:1004:1004::/home/zhaoritian:/bin/bash
    mahuateng:x:1005:1005::/home/mahuateng:/bin/bash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
另外,for还有特殊格式((…)),实现C语言风格的变量操作

累加1至100的和

  [root@CentOS7 data]# vim 1_100.sh
  #!/bin/bash
  sum=0
  for ((i=1;i<=100;i++));do
  let sum+=i
  done
  echo sum=$sum

  [root@CentOS7 data]# chmod +x 1_100.sh

  [root@CentOS7 data]# ./1_100.sh
  sum=5050

  [root@CentOS7 data]#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
打印一串随机数,显示其中最大值与最小值

  [root@CentOS7 data]# vim max_min.sh
  #!/bin/bash
  for ((i=0;i<10;i++));do
          N=$RANDOM
          echo -e "$N \c"
  if [ $i -eq 0 ];then
          MAX=$N
          MIN=$N
  else
          [ $N -gt $MAX ] && MAX=$N
          [ $N -lt $MIN ] && MIN=$N
                  # if [ $N -gt $MAX ];then
                  #       MAX=$N
                  # fi
                  # if [ $N -lt $MIN ];then
                  #       MIN=$N
                  # fi
  fi
  done
  echo
  echo
  echo MAX=$MAX
  echo
  echo MIN=$MIN
  
  [root@CentOS7 data]# chmod +x max_min.sh
  
  [root@CentOS7 data]# ./max_min.sh
  4963 19191 14443 11564 9807 9680 1872 16925 7612 10735

  MAX=19191

  MIN=1872
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
跳至文章尾部
zhanghailiangji 发表于 2023-11-11 19:41
zhanghailiangji 发表于 2023-11-11 19:36
seq的简略用法
seq命令用于产生从某个数到另外一个数之间的所有整数。

希望对群主有帮助
 楼主| zwlk 发表于 2023-11-11 19:45

额,完全不搭边啊,大概浏览了下,里边还有一些错误
zhanghailiangji 发表于 2023-11-11 19:47
zwlk 发表于 2023-11-11 19:45
额,完全不搭边啊,大概浏览了下,里边还有一些错误

可以,你在你发帖子那个地方删除帖子就可以了
110350 发表于 2023-11-12 10:25
对于“有几列数据就得操作几次”提从一个想法,就是在做数据替换前,做一个统计,统计A文件列标题在B文件中出现在的次数,如果出现了0次,在后续的数据替换中就跳过这一列。
 楼主| zwlk 发表于 2023-11-12 12:33
110350 发表于 2023-11-12 10:25
对于“有几列数据就得操作几次”提从一个想法,就是在做数据替换前,做一个统计,统计A文件列标题在B文件中 ...

我已经实现了,先统计a的行数,除去标题行,就是最终的文件个数,用大循环先套起来。
里边用数组记录a文件的变量值,再替换到b文件里就可以了。
Batcher 发表于 2023-11-12 12:53
test1.sh
[Bash shell] 纯文本查看 复制代码
#!/bin/bash
FileA="A.txt"
FileB="B.txt"
Key1=$(awk 'NR==1{print $1}' $FileA)
Key2=$(awk 'NR==1{print $2}' $FileA)
Key3=$(awk 'NR==1{print $3}' $FileA)
Key4=$(awk 'NR==1{print $4}' $FileA)
n=0
sed '1d' $FileA | while read V1 V2 V3 V4; do
    let n=n+1
    sed "s/$Key1/$V1/g; s/$Key2/$V2/g; s/$Key3/$V3/g; s/$Key4/$V4/g" $FileB > "C${n}.txt"
done

免费评分

参与人数 2吾爱币 +2 热心值 +2 收起 理由
110350 + 1 + 1 我很赞同!
zwlk + 1 + 1 谢谢@Thanks!

查看全部评分

 楼主| zwlk 发表于 2023-11-12 15:51
Batcher 发表于 2023-11-12 12:53
test1.sh
[mw_shl_code=bash,true]#!/bin/bash
FileA="A.txt"

大神来啦,我用的awk读俩文件,把a存到数组,在b文件用gsub替换,思路差不多
但是没想到用read,整体少敲了好多字符,你这个更简洁
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 17:42

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表