Shell脚本-读取文件并在某些文本不存在的情况下添加行

时间:2018-07-13 08:17:29

标签: bash shell

更新:感谢每个人的意见。我相信我要实现的目标会有些混乱。我已经在下面的修改中解决了这些问题。

原始问题:

关于shell脚本,我是个菜鸟,请尽我所能提出自己的建议。以下代码经过多次迭代才能达到这一点。

很抱歉,如果我不能回答这个问题,请问是为什么。

场景: IP电话配置服务器。 文件夹包含多个,其中大多数是.cfg文件。 其中,如果文件名以001565或805ec0开头,则添加带有“ sip.listen_port”的行。忽略其他一切。

问题: 我能够做到上面没有任何问题。但是,如果文件已经有这一行,我的脚本还会添加另一行。

预期结果: 我想做的是,读取文件,查看文本是否存在,然后添加该行。这是我失败的地方。

任何帮助我指出正确方向的方法,将不胜感激。

当前代码:

#!/bin/bash

#check old yealink phones are there
if ls 001565* 1> /dev/null 2>&1; then
    LOOP=0
    FILES=001565*
else
    LOOP=1
    FILES=805ec0*
fi

while [ $LOOP -lt 2 ]; do
    for f in $FILES
    do
        while read -r line; do
            if [[ "$line" =~ "sip.listen_port*" ]]; then                
                UNAME=$(awk '/user_name/{print $NF}' "$f")
                # take action on each file. $f store current file name
                # check the lenght of extension number and set the 
                if [ ${#UNAME} -lt 2 ]; then
                    echo "sip.listen_port = 900$UNAME" >> $f
                elif [ ${#UNAME} -lt 3 ]; then
                    echo "sip.listen_port = 90$UNAME" >> $f
                elif [ ${#UNAME} -lt 4 ]; then
                    echo "sip.listen_port = 9$UNAME" >> $f
                else
                    UNAME=${UNAME:(-3)}
                    echo "sip.listen_port = 9$UNAME" >> $f
                fi
            fi
        done < "$f"

    done
    #check new yealink phones are there
    if ls 805ec0* 1> /dev/null 2>&1; then
        FILES=805ec0*
        LOOP=$((LOOP+1))
    else
        LOOP=$((LOOP+2))
    fi
done

修改1: 为了减轻混乱,让我添加一张图片,显示典型文件夹中的文件以及典型文件的内容。

Folder structure

典型文件内容:

#!version:1.0.0.1
## the file header "#!version:1.0.0.1" can not be edited or deleted. ##

account.1.auth_name = 105
account.1.display_name = 105
account.1.enable = 1
account.1.label = 105
account.1.password = 
account.1.sip_server.1.address = pbx.dns.name
account.1.sip_server.2.address = 
account.1.user_name = 105

auto_provision.server.url = http://provisioning.url/

有效的方法: 该脚本将检查当前文件夹(以001565或805ec0开头的每个文件),并添加以下行。

sip.listen_port = 9XXX

我试图实现的是,如果以上行存在,则无需对该文件进行任何修改。

希望这有助于澄清所有问题。

3 个答案:

答案 0 :(得分:1)

无需阅读while ... done < "$f"的所有行。您可以改用简单的grep

for ...  
    if ! grep -q '^[[:blank:]]*sip\.listen_port' "$f"; then 
        ...
        ...
        echo "sip.listen_port = something" >> "$f"
    fi
done

如果您坚持使用while,则可以尝试以下操作:

for ...
    found=0
    while IFS= read -r line; do
        [[ $line =~ ^[[:blank:]]*"sip.listen_port" ]] && { found=1; break;}
    done < "$f"

    if ! ((found)); then
        ...
        ...
        echo "sip.listen_port = something" >> "$f"
    fi
done

答案 1 :(得分:0)

查看您的代码,我有一种感觉,如果您的文件包含“ sip.listen_port”,它将添加额外的一行,但是如果该行不存在,则不会添加。我是对的?如果是这种情况,那么您只需颠倒条件即可:

if [[ ! ("$line" =~ "sip.listen_port*") ]]; then

答案 2 :(得分:0)

如果我正确理解:

$ ll                      
total 4,0K
-rw------- 1 vkd vkd  0 июл 16 10:03 001565tmp.2rbFa0rT3G
-rw------- 1 vkd vkd  0 июл 16 10:03 001565tmp.6o5BywVcLF
-rw------- 1 vkd vkd  0 июл 16 10:03 805ec0tmp.220Jgcmv0e
-rw------- 1 vkd vkd  0 июл 16 10:03 805ec0tmp.7EGpvDw71e
-rw------- 1 vkd vkd 28 июл 16 10:03 805ec0tmp.F78rxzUBCz
$ cat *
sip.listen_port = something # only file 805ec0tmp.F78rxzUBCz has this entry

脚本:

#!/usr/bin/env bash
FILES_DIR=<your_path>
for filename in `ls $FILES_DIR | grep -E "^(001565|805ec0)"`
do
  if grep -q '^sip\.listen_port = something' $filename
  then
    continue
  else
    echo "sip.listen_port = something" >> $filename
  fi
done

结果:

$ ll
total 20K
-rw------- 1 vkd vkd 28 июл 16 10:03 001565tmp.2rbFa0rT3G
-rw------- 1 vkd vkd 28 июл 16 10:03 001565tmp.6o5BywVcLF
-rw------- 1 vkd vkd 28 июл 16 10:03 805ec0tmp.220Jgcmv0e
-rw------- 1 vkd vkd 28 июл 16 10:03 805ec0tmp.7EGpvDw71e
-rw------- 1 vkd vkd 28 июл 16 10:03 805ec0tmp.F78rxzUBCz

$ cat *       
sip.listen_port = something
sip.listen_port = something
sip.listen_port = something
sip.listen_port = something
sip.listen_port = something

P.S:我没有了解UNAME的逻辑...并且您的输出没有解释这个变量是什么,所以我决定它将是“某物”

UPD:

#!/usr/bin/env bash
FILES_DIR="<your_path>"

for filename in `ls $FILES_DIR | grep -E "^(001565|805ec0)"`
do
  if grep -qE '^sip.listen_port = [0-9]+' $filename
  then
    continue
  else
    uname=`awk '/^account.1.user_name = [0-9]+/ {print $3}' $filename`
    echo "sip.listen_port = 9$uname" >> $filename
  fi
done

之前:

$ ll
total 16K
-rw------- 1 vkd vkd 26 июл 16 16:36 001565tmp.2rbFa0rT3G
-rw------- 1 vkd vkd 53 июл 16 16:36 001565tmp.6o5BywVcLF
-rw------- 1 vkd vkd 28 июл 16 16:35 805ec0tmp.5ai0gFOkas
-rw------- 1 vkd vkd 25 июл 16 16:35 805ec0tmp.F78rxzUBCz

$ cat 001565tmp.2rbFa0rT3G 
account.1.user_name = 105

$ cat 001565tmp.6o5BywVcLF 
account.1.user_name = 21516
sip.listen_port = 921516

$ cat 805ec0tmp*          
account.1.user_name = 12345
account.1.user_name = 18

之后:

$ cat 001565tmp.*
account.1.user_name = 105
sip.listen_port = 9105
account.1.user_name = 21516
sip.listen_port = 921516

$ cat 805ec0tmp.*
account.1.user_name = 12345
sip.listen_port = 912345
account.1.user_name = 18
sip.listen_port = 918