简体   繁体   English

替换并计数无法通过awk和sed进行的bash

[英]replace and count bash unable through awk and sed

I need a bash script which should do the following: - read from an input file line by line which having format: [Environment]=[file name]=[property key]=[property value] - it will modify all files by replacing all properties in a $SOURCE directory according to the input file. 我需要一个bash脚本,该脚本应执行以下操作:-逐行读取具有以下格式的输入文件:[环境] = [文件名] = [属性键] = [属性值]-它将通过替换来修改所有文件根据输入文件将$ SOURCE目录中的所有属性。 Now I'm stuck at the point "replace and count". 现在,我被困在“替换并计数”这一点上。

The code until the "replace and count" phase: 直到“替换和计数”阶段的代码:

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

I have tried the following without success without success because value in properties can be any character (like: &,/,....): 我尝试了以下方法,但没有成功没有成功,因为属性值可以是任何字符(例如:&,/,....):

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

Also awk didn't worked as expected: 另外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"

And for input file: 对于输入文件:

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

I have the following output: 我有以下输出:

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

If I remove "&" from $NEW, everything goes fine. 如果我从$ NEW中删除“&”,一切正常。

You didn't post your expected output so it's a guess but this is probably what you want: 您没有发布预期的输出,因此只是一个猜测,但这可能是您想要的:

$ 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.

Note you cannot use gsub() as then you'll be in escaping hell just like if you used sed , instead you have to use index() and substr() as they operate on literal strings rather than regexps and backreferences in the replacements. 请注意,您不能使用gsub(),否则您将陷入困境,就像使用sed一样 ,相反,您必须使用index()和substr(),因为它们对文字字符串(而不是替换中的正则表达式和反向引用)进行操作。

Aside: always quote your shell variables and in shell use of all upper case is reserved for exported variables by convention while in both awk and shell you should avoid all upper case variable names anyway to avoid clashing with builtin variables. 撇开:总是引用您的shell变量,并且在shell中,按惯例,所有大写字母都用于导出的变量,而在awk和shell中,无论如何都应避免使用所有大写字母的变量名,以避免与内置变量发生冲突。

This is my solving through "sed" command which is doing exactly what I need. 这是我通过“ sed”命令执行的解决方案,该命令正是我所需要的。 I am not sure how fast it will run cause there will be a lot of properties to be changed when this script will be running. 我不确定它将运行多快,因为在运行该脚本时会有很多属性需要更改。

Guys please have a review over my solution, constructive feedback is welcomed: 伙计们,请对我的解决方案进行审查,欢迎提供建设性的反馈意见:

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

Also I succeeded with awk too with some sed for escaping Strings in my variables, which is different from sed: 我也用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')

And the replacement awk code would be something like this: 并且替换的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"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM