Issue
I have a directory that includes a lot of java files, and in each file I have a class variable:
String system = "x";
I want to be able to create a bash script which I execute in the same directory, which will go to only the java files in the directory, and replace this instance of x, with y. Here x and y are a word. Now this may not be the only instance of the word x in the java script, however it will definitely be the first.
I want to be able to execute my script in the command line similar to:
changesystem.sh -x -y
This way I can specify what the x should be, and the y I wish to replace it with. I found a way to find and print the line number at which the first instance of a pattern is found:
awk '$0 ~ /String system/ {print NR}' file
I then found how to replace a substring on a given line using:
awk 'NR==line_number { sub("x", "y") }'
However, I have not found a way to combine them. Maybe there is also an easier way? Or even, a better and more efficient way?
Any help/advice will be greatly appreciated
Solution
You may create a changesystem.sh
file with the following GNU awk
script:
#!/bin/bash
for f in *.java; do
awk -i inplace -v repl="$1" '
!x && /^\s*String\s+system\s*=\s*".*";\s*$/{
lwsp=gensub(/\S.*/, "", 1);
print lwsp"String system = \""repl"\";";
x=1;next;
}1' "$f";
done;
Or, with any awk
:
#!/bin/bash
for f in *.java; do
awk -v repl="$1" '
!x && /^[[:space:]]*String[[:space:]]+system[[:space:]]*=[[:space:]]*".*";[[:space:]]*$/{
lwsp=$0; sub(/[^[:space:]].*/, "", lwsp);
print lwsp"String system = \""repl"\";";
x=1;next
}1' "$f" > tmp && mv tmp "$f";
done;
Then, make the file executable:
chmod +x changesystem.sh
Then, run it like
./changesystem.sh 'new_value'
Notes:
for f in *.java; do ... done
iterates over all *.java files in the current directory-i inplace
- GNU awk feature to perform replacement inline (not available in a non-GNU awk)-v repl="$1"
passes the first argument of the script to theawk
command!x && /^\s*String\s+system\s*=\s*".*";\s*$/
- ifx
is false and the record starts with any amount of whitespace (\s*
or[[:space:]]*
), thenString
, any 1+ whitespaces,system
,=
enclosed with any zero or more whitesapces, and then a"
char, then has any text and ends with";
and any zero or more whitespaces, thenlwsp=gensub(/\S.*/, "", 1);
puts the leading whitespace in thelwsp
variable (it removes all text starting with the first non-whitespace char from the line matched)lwsp=$0; sub(/[^[:space:]].*/, "", lwsp);
- same as above, just in a different way sincegensub
is not supported in non-GNUawk
andsub
modifies the given input string (here,lwsp
){print "String system = \""repl"\";";x=1;next}1
- prints theString system = "
+ the replacement string +";
, assigns1
tox
, and moves to the next line, else, just prints the line as is.
Answered By - Wiktor Stribiżew Answer Checked By - Marilyn (WPSolving Volunteer)