5
\$\begingroup\$

In the script below I need to search in multiple files, and find a string, and replace with another.

It's basically version numbers (which need incrementing). Every time I find the old version number, and replace with a new version number.

The script is working well, but maybe has a cleaner way to search the old version number, because now I enter all the values manually.

It needs to be bulletproof, because if the file string version numbers changed with another third party app or script, the new version numbers must be the next number when running the script (currently, the version number check is done manually).

Can you give me any clues to improve the script?

oldVersion='1\.1\.10'
oldBuildNum='14'
oldVersionCode='22'
oldCurrentProjectVersion='20'

newVersion='1\.1\.11'
newBuildNum='15'
newVersionCode='23'
newCurrentProjectVersion='21'


canonical=$(cd -P -- "$(dirname -- "$0")" && printf '%s\n' "$(pwd -P)/")
xcodePath="${canonical}ios/Runner.xcodeproj/project.pbxproj"

sed -i -e "s/MARKETING_VERSION = ${oldVersion}/MARKETING_VERSION = ${newVersion}/g" "$xcodePath"
sed -i -e "s/FLUTTER_BUILD_NAME = ${oldVersion}/FLUTTER_BUILD_NAME = ${newVersion}/g" "$xcodePath"
sed -i -e "s/FLUTTER_BUILD_NUMBER = ${oldBuildNum}/FLUTTER_BUILD_NUMBER = ${newBuildNum}/g" "$xcodePath"
sed -i -e "s/CURRENT_PROJECT_VERSION = ${oldCurrentProjectVersion}/CURRENT_PROJECT_VERSION = ${newCurrentProjectVersion}/g" "$xcodePath"

pubspec="${canonical}pubspec.yaml"

# The version string format here is: version: 1.1.10+22 
sed -i -e "s/version: ${oldVersion}+${oldVersionCode}/version: ${newVersion}+${newVersionCode}/g" "$pubspec"

android="${canonical}android/local.properties"
sed -i -e "s/flutter\.versionName=${oldVersion}/flutter\.versionName=${newVersion}/g" $android
sed -i -e "s/flutter\.versionCode=${oldVersionCode}/flutter\.versionCode=${newVersionCode}/g" $android
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

A shell program ought to begin with an interpreter specification:

#!/bin/sh

It looks like oldVersion needs to be a regex, but newVersion is used as literal replacement, so shouldn't contain those backslashes.

It's very inefficient to repeatedly run sed in-place, compared to a single sed command for each file:

sed -i \
    -e "s/\(MARKETING_VERSION\|FLUTTER_BUILD_NAME\) = ${oldVersion}/\1 = ${newVersion}/g" \
    -e "s/\(FLUTTER_BUILD_NUMBER = \)${oldBuildNum}/\1${newBuildNum}/g" \
    -e "s/\(CURRENT_PROJECT_VERSION = \)${oldCurrentProjectVersion}/CURRENT_PROJECT_\1${newCurrentProjectVersion}/g" \
    "$xcodePath"

Depending on the input file, we might not need to use /g option (i.e. if the match won't occur multiple times on a given line). If those are whole lines, as in a key=value properties file, perhaps we want to replace everything after =, like this:

sed -i \
    -e "/^\(MARKETING_VERSION\|FLUTTER_BUILD_NAME\) /s/=.*/= ${newVersion}/" \
    -e "/^FLUTTER_BUILD_NUMBER /s/=.*/= ${newBuildNum}/" \
    -e "s/^CURRENT_PROJECT_VERSION /s/=.*/= ${newCurrentProjectVersion}/" \
    "$xcodePath"

Then we don't need to know what the old version was, just the new version we want to create.

I've even been known to write a function to create a sed program for such files:

#!/bin/bash
# (We need Bash, as we use a process substitution below)

# Output a sed script that sets each KEY to VALUE
change_values() {
    printf '/^%s *=/s/=.*/= %s/\n' "${@//\//\\/}"
}

change_xcode_file() {
    change_values \
        MARKETING_VERSION "$newVersion" \
        FLUTTER_BUILD_NAME "$newVersion" \
        FLUTTER_BUILD_NUMBER "$newBuildNum" \
        CURRENT_PROJECT_VERSION "$newCurrentProjectVersion"
}

sed -i -f <(change_xcode_file) "$xcodePath"

That might be overkill for you, but I found that useful in my project, where any developer might need to quickly adjust which things get overwritten in the config.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks, its great. I wondering that maybe is it possible to make this without giving the new version numbers? I mean to check the old values, and raise its number. What do you think about this? \$\endgroup\$
    – nszmmp
    Apr 5, 2022 at 16:26
  • \$\begingroup\$ Yes, I've seen that done - you'll obviously need a way to specify whether the major, minor or patch number is to be updated. You'll probably find Perl much easier than Sed for this (sed isn't great at arithmetic on its own). \$\endgroup\$ Apr 11, 2022 at 8:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.