【问题标题】:shell: Replacing a part of Line in a fileshell:替换文件中的部分行
【发布时间】:2015-12-20 11:15:33
【问题描述】:

我是 shell 编程的新手,必须完成以下任务。 我在第 28 行(静态)有以下行的文件。

page.sysauth = "Admin"

我想在每次创建新的 sysauth 条目时使用 shell 脚本替换这一行。

page.sysauth = {"Admin", "root"} page.sysauth = {"Admin", "root", "newAdmin"} 等等

我还想从这个 sysauth 变量中删除条目

page.sysauth = {"Admin", "root", "newAdmin"}
page.sysauth = {"Admin", "root"}
page.sysauth = "Admin"

请提供实现这一目标的指针。

编辑: 感谢您的输入: 假设:应该存在第一个条目。例如:page.sysauth="Admin" 当 page.sysauth=______(空)时脚本失败。

这是我的工作脚本 sysauth_adt.sh

#!/bin/bash
add () {
    sed -i~ -e '28 { s/= "\(.*\)"/= {"\1"}/; # Add curlies to a single entry.
                     s/}/,"'"$entry"'"}/     # Add the new entry.
                   }' "$file"
}

remove () {
    sed -i~ -e '28 { s/"'"$entry"'"//;      # Remove the entry.
                     s/,}/}/;               # Remove the trailing comma (entry was last).
                     s/{,/{/;               # Remove the leading comma (entry was first).
                     s/,,/,/;               # Remove surplus comma (entry was inside).
                     s/{"\([^,]*\)"}/"\1"/  # Remove curlies for single entry.
                   }' "$file"
}

if (( $# == 3 )) ; then
    file=$1
    action=$2
    entry=$3
    if [[ $action == add ]] ; then
        if head -n28 $1 | tail -n1 | grep -q $3 ; then
                echo 0 
        else
                add
        fi
    elif [[ $action == remove ]] ; then
        if head -n28 $1 | tail -n1 | grep -q $3 ; then
                remove
        else
                echo 0
        fi
    fi
else
    echo "Usage: ${0#*/} file (add | remove) entry" >&2
    exit 1
fi

【问题讨论】:

    标签: bash shell awk sed sh


    【解决方案1】:

    如果您的条目总是没有逗号的单个单词,您可以使用简单的 sed 脚本:

    #!/bin/bash
    add () {
        sed -i~ -e '28 { s/= "\(.*\)"/= {"\1"}/; # Add curlies to a single entry.
                         s/}/,"'"$entry"'"}/     # Add the new entry.
                       }' "$file"
    }
    
    remove () {
        sed -i~ -e '28 { s/"'"$entry"'"//;      # Remove the entry.
                         s/,}/}/;               # Remove the trailing comma (entry was last).
                         s/{,/{/;               # Remove the leading comma (entry was first).
                         s/,,/,/;               # Remove surplus comma (entry was inside).
                         s/{"\([^,]*\)"}/"\1"/  # Remove curlies for single entry.
                       }' "$file"
    }
    
    if (( $# == 3 )) ; then
        file=$1
        action=$2
        entry=$3
        if [[ $action == add ]] ; then
            add
        elif [[ $action == remove ]] ; then
            remove
        fi
    else
        echo "Usage: ${0#*/} file (add | remove) entry" >&2
        exit 1
    fi
    

    添加或删除条目时,脚本不会检查列表中是否已存在条目。对于更复杂的任务,我可能会切换到真正的编程语言。

    【讨论】:

    • 谢谢@choroba,您能否告诉我们如何单独检查该特定行号是否存在模式。这样可以避免重复。
    • @Tegra:正如我所提到的,我可能会为此使用 Perl。
    【解决方案2】:
    awk -F '[[:blank:]]+=[[:blank:]]+' '
       # load every single entry
       NR != 28 && FNR == NR && $1 ~ /^page.sysauth$/ && $0 !~ /\{.*\}/ { aSysAdd[ ++SysAdd] = $2}
       # load special line 28
       NR == 28 {
          gsub( /^{|}$/, "", Datas = $2)
          SysOrg = split( Datas, aSysOrg, /[[:blank:]]*,[[:blank:]]*/)
          }
       # print standard lines
       FNR != NR && $1 !~ /^page.sysauth$/ { print }
       # print line 28 (new version)
       FNR != NR && FNR == 28 {
          printf "page.sysauth = {" aSysOrg[ 1]
          for( i = 2; i <= SysOrg; i++) printf ", %s", aSysOrg[ i]
          for( i = 1; i <= SysAdd; i++) printf ", %s", aSysAdd[ i]
          print "}"
       # don't print other page.sysauth
       }
     ' YourFile YourFile > YourFile.new
    mv YourFile.new YourFile
    

    将 awk 与 2 读取一起使用(双精度 YourFile 不是错误并且是强制性的)

    【讨论】:

    • 谢谢你这个 awk 命令的输入参数是什么
    • 此示例中的文件YourFile,但您可以将其更改为任何文件全名。这意味着它不适用于流输入(不是这样)
    猜你喜欢
    • 2017-11-25
    • 1970-01-01
    • 2023-01-03
    • 1970-01-01
    • 2014-12-06
    • 2016-11-02
    • 2019-01-09
    • 1970-01-01
    • 2020-06-10
    相关资源
    最近更新 更多