zwlk 发表于 2023-11-11 11:29

Linux shell如何根据变量列表批量生成文本

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

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

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

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

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

zwlk 发表于 2023-11-11 15:29

自己研究出来了,不知道是不是最简便的。
这贴可以终结了,能够自己删帖吗?

zhanghailiangji 发表于 2023-11-11 19:36

seq的简略用法
seq命令用于产生从某个数到另外一个数之间的所有整数。

例如:列出1到7的数字

@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的数字

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

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

# seq99 2 105
99
101
103
105

# 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的数字

# seq 10 3
#
1
2
例如:显示10到3间隔为2的数字

# seq 10 2 3
#
1
2
for简略用法
格式 :

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

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

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

# 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

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

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

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

# 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

# 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结尾的文件。数量过多仅做部分展示

# 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便可以实现自动、快速、批量的修改文件名

# ls
f1.txtf2.txtf3.txtf4.logf5.logf6.logf7.pngf8.pngf9.png

# 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
    # chmod +x rename_file.sh   #给脚本添加执行权限
   
    # mv rename_file.sh ../   #由于脚本与文件在同一目录下,所以需要移走
   
    # cd ..   #进入上级目录

    # ./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

    # ls scripts/    查看核实结果
    f1.apkf2.apkf3.apkf4.apkf5.apkf6.apkf7.apkf8.apkf9.apk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
利用for还可以做什么呢?
利用for批量创建用户
编辑一个要创建的用户列表的文件

    # vim name.txt
    zhanglang
    mayun
    zhaoritian
    mahuateng

    # 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

    # vim batch_user.sh
   
    # chmod +x batch_user.sh
   
    # ./batch_user.sh
    zhanglang is created.
    mayun is created.
    zhaoritian is created.
    mahuateng is created.
   
    # 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的和

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

# chmod +x 1_100.sh

# ./1_100.sh
sum=5050

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

# 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

# chmod +x max_min.sh

# ./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:41
希望对群主有帮助

额,完全不搭边啊,大概浏览了下,里边还有一些错误{:1_926:}

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文件里就可以了。:lol

Batcher 发表于 2023-11-12 12:53

test1.sh
#!/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

zwlk 发表于 2023-11-12 15:51

Batcher 发表于 2023-11-12 12:53
test1.sh
#!/bin/bash
FileA="A.txt"


大神来啦,我用的awk读俩文件,把a存到数组,在b文件用gsub替换,思路差不多:lol
但是没想到用read,整体少敲了好多字符,你这个更简洁{:1_921:}{:1_921:}{:1_921:}
页: [1] 2
查看完整版本: Linux shell如何根据变量列表批量生成文本