Reputation: 19
I have a file:
...
version=1
...
subversion=2
..
I wish to display "version.subversion", so in current case "1.2".
What I currently have looks like this:
echo `echo -n $(grep "version=" file | awk -F= '{print $2 "."}'); grep -n "subversion=" file | awk -F= '{print $2}'`
So I have two separate greps following each other and the first one is wrapped into echo -n
to get rid of the space that I would otherwise have between them.
This works, but doesn't look ideal. Is there a better way to do this?
Upvotes: 0
Views: 708
Reputation: 7253
In some cases source
can do the job, for this test file:
$ cat file.txt
ls
some text
version=1
subversion=2
echo ok
$ ver=$(. file.txt &> /dev/null; echo "${version:-0}.${subversion:-0}")
$ echo $ver
1.2
Sourcing done in subshell so it won't change current env. All output and errors thrown to /dev/null
and echoed only needed info.
Upvotes: 0
Reputation: 52102
If you know for sure that the version
line comes first, you can do something like this:
$ grep -E '^(sub)?version=' infile | cut -d= -f2 | paste -sd.
1.2
which works as follows:
grep -E '^(sub)?version=' infile | # Get lines starting with "version"/"subversion"
cut -d= -f2 | # Print part after "="
paste -sd. # Join lines, separated by "."
And if the order is not deterministic, we can add a (reverse) sort step:
grep -E '^(sub)?version=' infile | sort -r | cut -d= -f2 | paste -sd.
Upvotes: 4
Reputation: 37394
Lol, so I wrote this awk and then noticed that almost every feature was in another answer (++) except quick exit once done and if version
or subversion
is missing, 0
is printed instead (ie. 1.0
or 0.2
):
$ awk -F\= ' # set field delimiter to =
$1~/^(sub)?version$/ { # only process sub- or version fields
a[$1]=$2 # hash key and value
if(a["version"] && a["subversion"]) # once both met
exit # no more need to process so exit
}
END { # in end or after exit
print ((v=a["version"])?v:0) "." ((v=a["subversion"])?v:0) # output value or 0
}' file
Output:
1.2
or:
1.0 # if missing subversion
or:
0.2 # if missing version
Upvotes: 1
Reputation: 15246
I also used awk
for a one-pass, one-proc solution. I quit
after subversion
to avoid wasted I/O and cycles, though this is likely a small enough task that it doesn't matter - just like to stay in the habit of being as efficient as possible in case the paradigm changes a little sometime in the future.
awk -F= '/^version/{v=$2}; /^subversion/{ printf "%d.%d\n",v,$2; quit; }' file
Upvotes: 0
Reputation: 361546
Let's simplify it one step at a time.
The outer echo `...`
can go. Backticks and echo are basically inverse operations and they (more or less) cancel out when combined.
echo -n "$(grep "version=" file | awk -F= '{print $2 "."}')"
grep -n "subversion=" file | awk -F= '{print $2}'
An easier way to combine the two lines is to embed them inside a single printout.
echo "$(grep "version=" file | awk -F= '{print $2}').$(grep "subversion=" file | awk -F= '{print $2}')"
Awk can both search and print. No need for grep.
echo "$(awk -F= '$1=="version" {print $2}' file).$(awk -F= '$1=="subversion" {print $2}' file)"
You could make this easier to read by using printf
to split it across multiple lines:
printf '%s.%s\n' \
"$(awk -F= '$1=="version" {print $2}' file)" \
"$(awk -F= '$1=="subversion" {print $2}' file)"
That looks pretty good. But you know what? This screams for a one-pass solution. Awk is a pretty capable mini-language in its own right. We could have it save all the key/value pairs into a map and then print the results at the end:
awk -F= '{map[$1]=$2} END {print map["version"] "." map["subversion"]}' file
Here {map[$1]=$2}
is executed for each line of the input file, saving the keys and values to a map. When the file is finished the END
block runs and prints the two desired fields with a .
in between.
Upvotes: 4
Reputation: 33854
One awk
solution:
$ awk -F"=" '/^version/ {v=$2;next} /^subversion/ {sv=$2} END {printf "%s.%s\n",v,sv}' file
1.2
Where:
-F"="
- input field separator/^*version/
- search patternsv/sv=$2
- store the 2nd fieldnext
- optional; skips to next input lineEND/printf
- output the results as v.sv
Upvotes: 1