Parsing an variable in search field in AWK: issue with syntax - bash
I read a few topics but still cannot solve the problem.
This is test file for example:
1:abc:100:/k/ll
2:abd:120:/k/gg
3:www:3:/k/ll
4:rrr:66:/k/gg
5:ddd:140:/k/ll
This is my code:
ZM=${2:-test}
VAR=$1
awk -F':' -v one="$VAR" '$4 ~ one $3 > 100' $ZM
I want for this script to write these lines, where the 3 field is greater than 100, and 4 field contains the string specified in the variable, eg. "ll".
For example:
./test.sh ll
Output:
1:abc:100:/k/ll
5:ddd:140:/k/ll
What am I doing wrong? Thanks for your responses!
FOR $3>100
awk -v FS=":" -v one=$VAR '{if($3>100 && $4~one){print $0}}' my_file
FOR $3>=100 (since your output is different from your request)
awk -v FS=":" -v one=$VAR '{if($3>=100 && $4~one){print $0}}' my_file
Related
Edit multiple columns in a line using awk command?
I'm trying to edit 3 columns in a file if the value in column 1 equals a specific string. This is my current attempt: cp file file.copy awk -F':' 'OFS=":" { if ($1 == "root1") $2="test"; print}' file.copy>file rm file.copy I've only been able to get the awk command working with one column being changed, I want to be able to edit $3 and $8 as well. Is this possible in the same command? Or is it only possible with separate awk commands or with a different command all together? Edit note: The real command i'll be passing variables to the columns, i.e. $2=$var It'll be used to edit the /etc/passwd file, sample input/output: root:$6$fR7Vrjyp$irnF38R/htMSuk0efLSnAten/epf.5v7gfs0q.NcjKcFPeJmB/4TnnmgaAoTUE9.n4p4UyWOgFwB1guJau8AL.:17976::::::
You can create multiple statements for the if condition with a block {}. awk -F':' 'OFS=":" { if ($1 == "root1") {$2="test"; $3="test2";} print}' file.copy>file You can also improve your command by using awk's default "workflow": condition{commands}. For this you need to bring the OFS to the input variables (-v flag) awk -F':' -v OFS=":" '$1=="root1"{$2="test"; $3="test2"; print}' file.copy>file
You may use # Fake sample values v1=pass1 v2=pass2 awk -v var1="$v1" -v var2="$v2" 'BEGIN{FS=OFS=":"} $1 == "root1" { $2 = var1; $3 = var2}1' file > tmp && mv tmp file See the online awk demo: s="root1:xxxx:yyyy root11:xxxx:yyyy root1:zzzz:cccc" v1=pass1 v2=pass2 awk -v var1="$v1" -v var2="$v2" 'BEGIN{FS=OFS=":"} $1 == "root1" { $2 = var1; $3 = var2}1' <<< "$s" Output: root1:pass1:pass2 root11:xxxx:yyyy root1:pass1:pass2 Note: -v var1="$v1" -v var2="$v2" pass the variables you need to use in the awk command BEGIN{FS=OFS=":"} set the field separator $1 == "root1" check if Field 1 is equal to some value { $2 = var1; $3 = var2 } set Field 2 and 3 values 1 calls the default print command file > tmp && mv tmp file helps you "shrink" the "replace-inplace-like" code.
Need to use awk to get a specific word or value after another specific word?
I need to use awk to get a specific word or value after another specific word, I tried some awk commands already but after many other filters like grep and sed. The file that I need to get the word from is having the same line more than one time like the below line: Configuration: number=6 model=MSA SNT=4 IC=8 SIZE=16384MB NRF=24 meas=2.00 If need 24 I used grep IC file | awk 'NF>1{print $NF}' If need 16384MB I used grep IC file | awk -F'SIZE=' '{ print $2 }'|awk '{ print $1 }' We need to get any word from that line using awk? what I used can get what is needed but we still need a minimized awk command. I am sure we can use one single awk to get the needed info from one line minimized command?
sed -r 's/.*SIZE=([^ ]+).*/\1/' input 16384MB sed -r 's/.*NRF=([^ ]+).*/\1/' input 24 grep way : grep -oP 'SIZE=\K[^ ]+' imput 16384MB awk way : awk '{for(i=1;i<=NF;i++) if($i ~ /SIZE=/) split($i,a,"=");print a[2]}' input
You could use an Awk with multi-character de-limiter as below to get this done. Loop through the fields, match the pattern you need and print the next field which contains the field value. awk -F'[:= ]' -v option="${match}" '{for(i=1;i<=NF;i++) if ($i ~ option) {print $(i+1)}}' file Examples, match="number" awk -F'[:= ]' -v option="${match}" '{for(i=1;i<=NF;i++) if ($i ~ option) {print $(i+1)}}' file 6 match="model" awk -F'[:= ]' -v option="${match}" '{for(i=1;i<=NF;i++) if ($i ~ option) {print $(i+1)}}' file MSA match="meas" awk -F'[:= ]' -v option="${match}" '{for(i=1;i<=NF;i++) if ($i ~ option) {print $(i+1)}}' file 2.00
here is a more general approach ... | awk -v k=NRF '{for(i=2;i<=NF;i++) {split($i,a,"="); m[a[1]]=a[2]} print m[k]}' code will stay the same just change the key k.
If you have GNU awk you could use the third parameter of match: $ awk 'match($0,/( IC=)([^ ]*)/,a)&& $0=a[2]' file 8 Or get the meas: $ awk 'match($0,/( meas=)([^ ]*)/,a)&& $0=a[2]' file 2.00 Should you use some other awk, you could use this combination of split, substr and match: $ awk 'split(substr($0,match($0,/ IC=[^ ]*/),RLENGTH),a,"=") && $0=a[2]' file 8
Using awk to search for a line that starts with but also contains a string
I have a file that has multiple lines that starts with a keyword. I only want to modify one of them and it's easy to distinguish the two. I want the one that is under the [dbinfo] section. The domain name is static so I know that won't change. awk -F '=' '$1 ~ /^dbhost/ {print $NF};' myfile.txt myfile.txt [ual] path=/web/ dbhost=ez098sf [dbinfo] dbhost=ec0001.us-east-1.localdomain dbname=ez098sf_default dbpass=XXXXXX
You can use this awk command to first check for presence of [dbinfo] section and then modify dbhost parameter: awk -v h='newhost' 'BEGIN{FS=OFS="="} $0 == "[dbinfo]" {sec=1} sec && $1 == "dbhost"{$2 = h; sec=0} 1' file [ual] path=/web/ dbhost=ez098sf [dbinfo] dbhost=newhost dbname=ez098sf_default dbpass=XXXXXX
You want to utilize a little bit of a state machine here: awk -F '=' ' $0 ~ /^\[.*\]/ {in_db_info=($0=="[dbinfo]"} $0 ~ /^dbhost/{if (in_db_info) print $2;}' myfile.txt
You can also do it with sed: sed '/\[dbinfo\]/,/\[/s/\(^dbhost=\).*/\1domain.com/' myfile.txt
grep/awk specific lines based on specific fields; using ksh variable with awk
I have this input file: file_in.txt (delimited by pipe) 3345:tyg|rty|27|0|0|ty6|{89|io|}62|0 3346:tyg|rtyuio|63|0|1|ty6|{89|gh|}45|0 3347:tyu|ray|24|0|0|ty6|{89|uh|}27|0 3348:tyg|rtoy|93|0|1|ty6|{89|yh|}1|0 3349:tyo|rtert|28|0|0|ty6|{89|gh|}27|0 I want to get only those lines which have 9th field value as }27 using '|' as delimiter so that my output should be: 3347:tyu|ray|24|0|0|ty6|{89|uh|}27|0 3349:tyo|rtert|28|0|0|ty6|{89|gh|}27|0 Below command works fine: awk -F"|" '{ if ($9 == "}27") print $0 }' file_in.txt But I want to use a shell variable instead of "}27" for which I tried this: taskid="}27" awk -v tid="$taskid" -F"|" '{ if ($9 == "}tid") print $0 }' file_in.txt Please help me figure out where I am going wrong with this command. Any other command suggestions to achieve the same are appreciated.
This should work: taskid="}27" awk -F'|' -v tid="$taskid" '$9 == tid' file Output: 3347:tyu|ray|24|0|0|ty6|{89|uh|}27|0 3349:tyo|rtert|28|0|0|ty6|{89|gh|}27|0
Assuming your shell variable $tasked has the value 27, you want to use one of these forms: build the string with the open brace in the shell awk -v tid="}$taskid" -F"|" '$9 == tid' file or do it in awk --- awk's string concatenation is just placing strings side-by-side with optional whitespace in between awk -v tid="$taskid" -F"|" '$9 == "}" tid' file
Your own command should have worked with this change: $ ksh $ taskid=}27 $ awk -v tid=$taskid -F"|" '{ if ($9 == tid) print $0}' file_in.txt Output: 3347:tyu|ray|24|0|0|ty6|{89|uh|}27|0 3349:tyo|rtert|28|0|0|ty6|{89|gh|}27|0
Replace multiple value of csv file
I have a csv file : 1,1,1,2 2,2,1,2 3,3,1,2 4,4,1,2 5,5,1,2 6,6,1,2 7,7,1,2 8,8,1,2 9,9,1,2 10,10,2,2 11,11,2,2 12,12,2,2 13,13,3,2 I want to replace each third value to this : If 1; then 22 If 2; then 35 If 3; then 14 This is what I have made : awk -F , -v OFS=, '{if ($3=="1") $3="22";if ($3=="2") $3="35";if ($3=="3") $3="14"} {print "\""$1"\""",""\""$2"\""",""\""$3"\""",""\""$4"\""}' /tmp/test.csv It's work well on Debian but not on Ubuntu. What is the problem ? Thanks you [EDIT] With the example I cited yesterday, it works , but not with this one : cat -v test.csv 1,1,1,2 2,2,1,2 3,3,1,2 4,4,1,2 5,5,1,2 6,6,1,2 7,7,1,2 8,8,1,2 9,9,1,2 10,10,1,2 11,11,1,2 12,12,1,2 13,13,1,2 14,14,1,2 15,15,1,2 16,16,1,2 17,17,1,2 18,18,1,2 19,19,1,2 20,20,1,2 21,21,1,2 22,22,1,2 23,23,1,2 24,24,1,2 25,25,1,2 26,26,1,2 27,27,1,2 28,28,1,2 29,29,1,2 30,30,1,2 31,31,1,2 32,32,1,2 33,33,1,2 34,34,1,2 35,35,1,2 36,36,1,2 37,37,1,2 38,38,1,2 39,39,1,2 40,40,1,2 And now, the command return : awk -F , -v OFS=, '{if ($3=="1") $3="2";if ($3=="2") $3="3";if ($3=="3") $3="5"} {print "\""$1"\""",""\""$2"\""",""\""$3"\""",""\""$4"\""}' toast.csv "1","1","5","2" "2","2","5","2" "3","3","5","2" "4","4","5","2" "5","5","5","2" "6","6","5","2" "7","7","5","2" "8","8","5","2" "9","9","5","2" "10","10","5","2" "11","11","5","2" "12","12","5","2" "13","13","5","2" "14","14","5","2" "15","15","5","2" "16","16","5","2" "17","17","5","2" "18","18","5","2" "19","19","5","2" "20","20","5","2" "21","21","5","2" "22","22","5","2" "23","23","5","2" "24","24","5","2" "25","25","5","2" "26","26","5","2" "27","27","5","2" "28","28","5","2" "29","29","5","2" "30","30","5","2" "31","31","5","2" "32","32","5","2" "33","33","5","2" "34","34","5","2" "35","35","5","2" "36","36","5","2" "37","37","5","2" "38","38","5","2" "39","39","5","2" "40","40","5","2" All third values are equal to 5 instead of 2. Same issue with this example on Debian.
None of the code you have posted will behave differently on any given machine vs any other machine. You saying that it did and posting the wrong code initially was a red herring, you just have buggy code, that's all. The code you added in your latest edit says: if ($3=="1") $3="2";if ($3=="2") $3="3";if ($3=="3") $3="5" So let's say you start with a $3 in your input file that has value 1. Your first test/assignment is if ($3=="1") $3="2" so after that code executes $3 has value 2. Now your second test/assignment is if ($3=="2") $3="3" Well, $3 IS now 2 after your first code segment executes, so now it gets set to 3. And then your next test/assignment sets it to 5. So given a $3 that is 1 you set $3 to 2, then you set it to 3 then you set it to 5 - net result is it's always 5. Throw in in some "else"s: if ($3=="1") $3="2"; else if ($3=="2") $3="3"; else if ($3=="3") $3="5" but at least change your script to avoid having to print each field individually: awk -F, -v OFS='","' '{if ($3=="1") $3="2"; else if ($3=="2") $3="3"; else if ($3=="3") $3="5"} {print "\""$0"\""}' toast.csv and consider using a more idiomatic approach: $ cat file 9,9,1,2 10,10,2,2 13,13,3,2 $ awk -F, -v OFS='","' 'BEGIN{split("2,3,5",m)} {$3=m[$3]} {print "\""$0"\""}' file "9","9","2","2" "10","10","3","2" "13","13","5","2" The above assume your $3 is always one of the values you show/test for. If not there's easy tweaks. In general to map one set of arbitrary numbers to another and allow for some input data that doesn't need to get mapped: $ awk -F, -v OFS='","' 'BEGIN{split("1,2,3",a); split("2,3,5",b); for (i in a) m[a[i]]=b[i]} {$3=($3 in m ? m[$3] : $3)} {print "\""$0"\""}' file "9","9","2","2" "10","10","3","2" "13","13","5","2" or if you prefer: $ awk -F, -v OFS='","' 'BEGIN{split("1,2,2,3,3,5",t); for (i=2;i in t;i+=2) m[t[i-1]]=t[i]} {$3=($3 in m ? m[$3] : $3)} {print "\""$0"\""}' file "9","9","2","2" "10","10","3","2" "13","13","5","2"
It might be easier with sed: sed 's/\([0-9]*,[0-9]*,\)1\(,[0-9]*\)/\122\2/' /tmp/test.csv sed 's/\([0-9]*,[0-9]*,\)2\(,[0-9]*\)/\135\2/' /tmp/test.csv sed 's/\([0-9]*,[0-9]*,\)3\(,[0-9]*\)/\114\2/' /tmp/test.csv I believe that should do the trick and will most likely work on most sh/bash environments. EDIT: Note that this just prints out the actual replacements each command does, so you know what is going to happen before you actually change anything. You may want to first back up your file and then do inplace replacements with the -i flag: $ cat /tmp/test.csv 1,1,1,2 2,2,1,2 3,3,1,2 4,4,1,2 5,5,1,2 6,6,1,2 7,7,1,2 8,8,1,2 9,9,1,2 10,10,2,2 11,11,2,2 12,12,2,2 13,13,3,2 $ cp /tmp/test.csv /tmp/test.csv.bak $ sed -i 's/\([0-9]*,[0-9]*,\)1\(,[0-9]*\)/\122\2/' /tmp/test.csv $ sed -i 's/\([0-9]*,[0-9]*,\)2\(,[0-9]*\)/\135\2/' /tmp/test.csv $ sed -i 's/\([0-9]*,[0-9]*,\)3\(,[0-9]*\)/\114\2/' /tmp/test.csv $ cat /tmp/test.csv 1,1,22,2 2,2,22,2 3,3,22,2 4,4,22,2 5,5,22,2 6,6,22,2 7,7,22,2 8,8,22,2 9,9,22,2 10,10,35,2 11,11,35,2 12,12,35,2 13,13,14,2