0

I have a file and I am trying to find and replace a string of text. The contents of the file are:

/**
 * Version:      1.5.1
 * Tested up to: 5.8
**/

I am trying to append the commit hash onto the version number inside of a file using a combination of awk and sed, but am having a difficult time. Previously, this was working just fine but is no longer working properly:

VERSION_LINE=$(awk '/\* Version:/' style.css)
COMMIT_HASH=$(git rev-parse --verify HEAD | head -c 7)
sed -i -e "${VERSION_LINE}s/$/-${COMMIT_HASH}/" style.css

I expect $VERSION_LINE to return * Version: 1.5.1 but Checking contents it, it's actually returning a bunch of file names (which don't contain the string) AND that line at the end.

$ echo $VERSION_LINE;
404.php LICENSE archive.php comments.php dist footer.php functions.php header.php includes index.php page.php partials readme.txt screenshot.png search.php searchform.php single.php style.css woocommerce woocommerce.php Version: 1.5.1

But when I run awk '/\* Version:/' style.css it does return the correct line, but storing it in a variable via VERSION_LINE=$(awk '/\* Version:/' style.css) is returning a bunch of file names. Why the difference?

Trying the following is also returning the incorrect value:

$ $VERSION_LINE=$(cat style.css | grep '* Version:')
$ -bash: 404.php: command not found

Works Fine:

$ awk '/\* Version:/' style.css
$ * Version:      1.5.1

Does Not Work:

$ VERSION_LINE=$(awk '/Version:/' style.css)
$ echo $VERSION_LINE
404.php Gruntfile.js LICENSE README.md archive.php changelog.txt comments.php composer.json composer.lock cypress.json docs footer.php functions.php header.php includes index.php languages manifest.xml package.json page.php partials phpcs.xml phpunit.xml postcss.config.js readme.txt screenshot.png search.php searchform.php single.php style.css vendor woocommerce woocommerce.php yarn.lock Version: 1.5.1

Current Version of Bash:

$ bash --version
$ GNU bash, version 5.1.4(1)-release (x86_64-pc-linux-gnu)
EHerman
  • 1,852
  • 7
  • 32
  • 52
  • 1
    Quote your variable: `echo "$VERSION_LINE"`. Otherwise the `*` is processed as a wildcard. – Barmar Nov 16 '21 at 00:35
  • Thanks @Barmar that looks like it's working. But the sed command is throwing an error now when using those variables. `$sed "${VER_NUMBER}/$/${VER_NUMBER}-${COMMIT_HASH}/" style.css` Error: `sed: -e expression #1, char 2: unknown command: `.'` – EHerman Nov 16 '21 at 00:53
  • 1
    You need `/` around the regexp when using it as an address. But you'll have another problem because the `*` in the Version line will be treated as a regexp quantifier. You need to escape the `*`. – Barmar Nov 16 '21 at 00:57

2 Answers2

0

You can do this with awk only:

awk -v hash="${COMMIT_HASH}" '/\* Version:/{$3=$3""hash}1' style.css > style.css.tmp \
    && mv style.css.tmp style.css
hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • I'm seeing a `awk: improper assignment: -v hash` error. Edit: I see, it should be -v hash="${COMMIT_HAS}". It looks like its working fairly well. Is there a way to preserve the spacing both before the `*` and inbetween `Version:` and the actual Version number? – EHerman Nov 16 '21 at 00:40
  • 1
    It should be `-v hash="${COMMIT_HASH}"` – Barmar Nov 16 '21 at 00:57
0

The immediate problem is that you need to quote the assignment to prevent the shell from expanding the literal *:

tripleee$ ls
foo bar baz
tripleee$ poo=$(echo '*')
tripleee$ echo "$poo"
foo bar baz
tripleee$ poo="$(echo '*')"
tripleee$ echo "$poo"
*

But the whole diversion to use Awk to find the line you want to replace is unnecessary (and basically a variation of Counting lines or enumerating line numbers so I can loop over them - why is this an anti-pattern?) -- you can easily use sed itself to find the line.

commit_hash=$(git rev-parse --verify HEAD | head -c 7)
sed -i -e "/\* Version:/s/$/-${commit_hash}/" style.css

(Notice also the use of lower case for private variables.)

tripleee
  • 175,061
  • 34
  • 275
  • 318