【问题标题】:replace and count bash unable through awk and sed无法通过 awk 和 sed 替换和计数 bash
【发布时间】:2016-08-26 04:14:43
【问题描述】:

我需要一个 bash 脚本,它应该执行以下操作: - 从输入文件中逐行读取,格式为:[Environment]=[file name]=[property key]=[property value] - 它将根据输入文件通过替换 $SOURCE 目录中的所有属性来修改所有文件。 现在我被困在“替换和计数”这一点上。

直到“替换和计数”阶段的代码:

PROPERTIES_LIST=/home/user/test_scripts/envPropList.txt

SOURCE=/home/user/test_scripts/source-directory

PROPERTIES_LOCATION=/WEB-INF/classes/

PROPERTIES_SOURCE=$SOURCE$PROPERTIES_LOCATION

ENV=$1
echo "> Update for ENVIRONMENT: $ENV... Please wait!"

NR=1
while read line; do
    IFS== read env prop <<< "$line"
    if [[ $env == $ENV]]
    then
        IFS== read file key value <<< "$prop"
        if [[ -z $file ]] || [[ -z $key ]] || [[ -z $value ]]
        then
            echo "> [ERROR] [LINE $NR] - WRONG/MISSING PROPERTY: $line"
        else
            //MODIFY $file BY  REPLACE AND COUNT
            //IF $key IS NOT FOUND AT ALL AN ERROR MESSAGE SHOULD BE DISPLAYED. ITERATION SHOULD CONTINUE
            //IF $key IS FOUND MORE THEN ONCE, A WARNING MESSAGE SHOULD BE DISPLAYED. ITERATION SHOULD CONTINUE

            echo "done"
        fi
    fi
    NR=$(( $NR + 1 ))
done <$PROPERTIES_LIST

我尝试了以下但没有成功,因为属性中的值可以是任何字符(例如:&、/、....):

COUNT=$(grep -c "$key" $PROPERTIES_SOURCE$file)
sed -i "s/${OLD}/${NEW}/g" $PROPERTIES_SOURCE$file

awk 也没有按预期工作:

DEST=/home/user/test_scripts/test.txt
OLD='asd.asd'
NEW='test/test?test.test&test=test'
COUNT=$(grep -c "$OLD" $DEST)
#sed -i "s/#${OLD}#/#${NEW}#p/g" $DEST
#echo "$OLD=$NEW"
echo "nr de rezultate: "$COUNT
awk -v OLD=$OLD -v NEW=$NEW '
    ($0 ~ OLD) {gsub(OLD, NEW); count++}1
    END{print count " substitutions occured."}
' "$DEST"

对于输入文件:

asd.asd
ewrqfg
qweasd.asdqwreqe
asd asd.asd
egd
test

我有以下输出:

test/test?test.testasd.asdtest=test
ewrqfg
qwetest/test?test.testasd.asdtest=testqwreqe
test/test?test.testasd asdtest=test.asd
egd
test

如果我从 $NEW 中删除“&”,一切都会正常。

【问题讨论】:

    标签: bash awk replace sed count


    【解决方案1】:

    您没有发布预期的输出,所以这是一个猜测,但这可能是您想要的:

    $ cat tst.sh
    dest='file'
    old='asd.asd'
    new='test/test?test.test&test=test'
    count=$(grep -c "$old" "$dest")
    #sed -i "s/#${old}#/#${new}#p/g" "$dest"
    #echo "$old=$new"
    echo "nr de rezultate: $count"
    awk -v old="$old" -v new="$new" '
        {
            head = ""
            tail = $0
            lgth = length(old)
            while ( start = index(tail,old) ) {
                head = head substr(tail,1,start-1) new
                tail = substr(tail,start+lgth)
                count++
            }
            print head tail
        }
        END { print count+0, "substitutions occured." }
    ' "$dest"
    
    $ ./tst.sh file
    nr de rezultate: 3
    test/test?test.test&test=test
    ewrqfg
    qwetest/test?test.test&test=testqwreqe
    asd test/test?test.test&test=test
    egd
    test
    3 substitutions occured.
    

    请注意,您不能使用 gsub(),因为您将在 escaping hell just like if you used sed 中,而是必须使用 index() 和 substr(),因为它们对文字字符串进行操作,而不是替换中的正则表达式和反向引用。

    除此之外:始终引用您的 shell 变量,并且在 shell 中,所有大写字母的使用按惯例保留用于导出的变量,而在 awk 和 shell 中,您应该避免使用所有大写的变量名,以避免与内置变量发生冲突。

    【讨论】:

      【解决方案2】:

      这是我通过“sed”命令解决的问题,这正是我需要的。我不确定它的运行速度有多快,因为在运行此脚本时会有很多属性需要更改。

      请大家对我的解决方案进行审核,欢迎提供建设性反馈:

      PROPERTIES_SOURCE=$SOURCE$PROPERTIES_LOCATION
      
      MEDIUM=$1
      echo "> Update release for ENVIRONMENT: "$MEDIUM"... Please wait!"
      
      if [[ -z $1 ]]
      then
          echo "> [ERROR] - Illegal script use. You have to send one of the following parameters representing environment name which will be updated:"
          echo "> [ERROR] - DEV ST UAT PROD"
          echo "> [ERROR] - Example: ./updateEnv.sh PROD"
          exit
      fi
      
      nr=1
      while read -r line; do
          IFS== read -r env prop <<< "$line"
          if [[ $env == $MEDIUM ]]
          then
              IFS== read -r file key value <<< "$prop"
              if [[ -z $file ]] || [[ -z $key ]] || [[ -z $value ]]
              then
                  echo "> [ERROR] [LINE $NR] - wrong or missing property: $line"
              else
                  esc_key=$(echo $key | sed -e 's/\./\\./g')
                  esc_val=$(echo $value | sed -e 's/\&\|\.\|\\\|\/\|\%/\\&/g')
                  occurances=$(grep -c "$key=" "$PROPERTIES_SOURCE$file")
                  if [[ $occurances > 1 ]]
                  then
                      echo "> [WARNING] [LINE $NR] - key found $occurances times: $key"
                  elif [[ $occurances < 1 ]]
                  then
                      echo "> [ERROR] [LINE $NR] - key was not found: $key"
                  fi
                  sed -i "s/${esc_key}=.*/${esc_key}=${esc_val}/g" $PROPERTIES_SOURCE$file
              fi
          fi
          nr=$(( $nr + 1 ))
      done <$PROPERTIES_LIST
      

      我也成功地使用了 awk,其中一些 sed 用于在我的变量中转义字符串,这与 sed 不同:

      STRING_OLD='asd.asd'
      STRING_NEW='!@#$%^&*()_+-=[]\{}|;"<>~`'
      OLD=$(echo $STRING_OLD | sed -e 's/\./\\\\./g')
      NEW=$(echo $STRING_NEW | sed -e 's/\&\|\\/\\\\&/g')
      

      替换的 awk 代码是这样的:

      awk -v OLD="$OLD" -v NEW="$NEW" '
          BEGIN {print "OLD:"OLD" and NEW:"NEW}
              ($0 ~ OLD) {gsub(/OLD=.*/,OLD=NEW);}1
      ' "$DEST" > "DEST.tmp" mv "DEST.tmp" "$DEST"
      

      【讨论】:

        猜你喜欢
        • 2020-02-03
        • 1970-01-01
        • 1970-01-01
        • 2016-10-30
        • 2019-07-20
        • 1970-01-01
        • 2017-11-11
        • 2019-08-07
        • 1970-01-01
        相关资源
        最近更新 更多