1

For this project, we have hundreds of applications using composer.json. I'm using a Bash script to go through and update the version numbers of any file that contain an application that is getting a new version.

For example, the original file looks like this (I put in only the relevant parts):

{
"name" : "test/graylogger"
"version" : "1.1.1"
...
"require": {
    "test/phpunit": "4.8.23"
}

I want to update it to this:

{
"name" : "test/graylogger"
"version" : "1.1.2"
...
"require": {
    "test/phpunit": "4.8.24"
}

But, it is ending up like this (which I don't want):

{
"name" : "1.1.2"
"version" : "1.1.2"
...
"require": {
    "test/phpunit": "4.8.24"
}

Basically, my script is supposed to be searching for 'version', updating the second quote after this up by one, and then looping through based on the folder file name (in this case, 'graylogger'), and then upping that in any other folders that contain that application. But for some reason, it's also updating the name, which I don't want. Here is my snippet of code that is doing this:

while read line2; do

   line1="$line1\"" #I did this to prevent any repetitive names from upping twice
   original=$(grep -hr "$line1" /Websites/"$line2"/composer.json | awk -F \" '{print $4}')

   if [["$original" != *"$line1"*]]; then
      sed -i'' s,"$original","$version",g composer.json

done < websites.txt

line1 is the application that is being updating within the file.

line2 is the file that is being updated.

I tried to make an if statement that excludes the change if the text in the second includes the name of the application, it doesn't update, but it doesn't seem to be working.

This is being done on a Mac.

Thanks!

  • 4
    I would really encourage using something like jq for structured data like this instead of trying to grep & sed it out, but that doesn't answer your direct question. – Michael Homer Apr 15 at 1:25
  • Your shell script has syntax errors and it won't work at all. – mosvy Apr 15 at 2:34
1

jq is a tool for processing JSON on the command line, and is more suitable for processing structured data like this than rudimentary textual modifications. Here is some jq that seems to match up with what you actually want to do:

program=test/graylogger
version=1.1.2
jq --arg prog "$program" --arg version "$version" '
    (.. | select(.name? == $prog).version) = $version
    |   (.. | select(has($prog)?)[$prog]) = $version' composer.json | sponge composer.json

The jq program itself is the two lines in single quotes.

It will replace both the "version" property of any object whose "name" is test/graylogger (the first line of the jq program) and thetest/grayloggerproperty of any object that has one (the second line of thejqprogram) with the new version. You can edit to only one or the other as appropriate - the pipe|` at the start of the second line is to separate them both, so if you only have one you can take it out.

The first line works by finding any suitable object with ..|select(.name? == $prog): look at every value (..) and keep looking at only the ones whose name is what we're looking for (and that have a name at all), and then by setting the version property on that object (.version = $version).

The second line similarly picks out any object that has a key matching the program name, and then updates that property using [] indexing.

I've used sponge from moreutils to replicate the sed -i behaviour of overwriting the file in-place. You could use a temporary file instead. All of this can go inside whatever your existing loop structure is to be applied to all of your files.

  • Thank you, I will try using jq and your suggestions – Glitteropia Apr 15 at 15:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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