-1

I have a set of JSON files in a local folder. What I want to do is change a particular string value in it, permanently. That means, deleting or modifying the old entry, writing a new one, and saving it.

Below is the format of the file:

{
  "name": "ABC #1",
  "description": "This is the description",
  "image": "ipfs://NewUriToReplace/1.png",
  "dna": "a56c520f57ba2a861de8c78099b4691f9dad6e87",
  "edition": 1,
  "date": 1641634646966,
  "creator": "Team Dreamlabs",
  "attributes": [
    {

I want to change ABA #1 to ABC #9501 in this file, ABC #2 to ABC #9502 in the text file, and so on. How do I do that on MAC in one go?

sajjad rezaei
  • 945
  • 1
  • 10
  • 23
  • Open any text editor that allows you to search and replace. Search for `#` and replace it with `#950`. I recommend vscode.dev if you don't have any. – MrFrenzoid Jan 08 '22 at 10:30

2 Answers2

0

As I understand from the example, you are adding a value of 9500 to your integers after the symbol #.

Because this kind of a replacement is a kind of string operation, a cycle with command sed might be used:

for f in *.json; do sed -i.bak 's/\("name": "ABC #\)\([0-9]\)",/\1950\2",/' $f; done

it just replaces a single digit to the new composition... Despite it responses to the example, obviously, it would not work for more than number #9.

Then we need to use a bash function:

function add_number() { old_number=$(cat $1 | sed -n 's/[ ]*"name": "ABC #\([0-9]*\)",/\1/p'); new_number=$(($old_number+9500)); sed -i.bak "s/\(\"name\": \"ABC #\)\([0-9]*\)\",/\1${new_number}\",/" $1; }; for f in *.json; do add_number $f ; done

The function add_number extracts the integer value, then adds a desired number to it and then replaces content of the file.

For both extraction and replacing the sed is used again.

At extraction flag -n allows to limit the amount of lines at sed output and mode p prints the result of replacement. Also, we do not want spaces symbols to pass into this assignment.

At replacement double quotes used in order to enable the bash to use the variable value inside of sed. Also, the real quotes are masked.

Regarding addition from the comment below, in order to make replacement in another line with tag edition (and using the same number), just a new replacement sed operation should be added with amended regular expression to fit this line.

Finally, the overall code in a better look:

function add_number() {
  old_number=$(cat $1 | sed -n 's/[ ]*"name": "ABC #\([0-9]*\)",/\1/p')
  new_number=$(($old_number+9500))
  sed -i.bak "s/\(\"name\": \"ABC #\)[0-9]*\",/\1${new_number}\",/" $1
  sed -i.bak "s/\(\"edition\": \)[0-9]*,/\1${new_number},/" $1
}
for f in *.json
  do add_number $f
done

Those previous answers helped me to write this code:

  • Thank you so much, it solved half my problem, but if you see my code, I missed another part which says **"edition": 1,** which I missed. Need to change that also (adding 9500) ... it will be great if you can help me change that under the same code. Thanks again! – Debashis Dey Jan 08 '22 at 13:33
  • Hi @DebashisDey, no problem, I edited the final code to meet your request. Please check. NB: the _*.bak_ files might be removed in a batch later using command like `rm *.json.bak` – Dmitry Kravtsov Jan 08 '22 at 14:07
0

If you are going to manipulate your JSON files on more than just this one occasion, then you might want to consider using tools that are designed to accomplish such tasks with ease.

One popular choice could be jq which is a "lightweight and flexible command-line JSON processor" that "has zero runtime dependencies" and is also available for OS X. By using jq within your shell, the following would be one way to accomplish what you have asked for.

Adding the numeric value 9500 to the number sitting in the field called edition:

jq '.edition += 9500' file.json

Interpreting a part of a string as number, adding again 9500 to it, and recomposing the string:

jq '.name |= ((./"#" | .[1] |= "\(tonumber + 9500)") | join("#"))' file.json

On the whole, iterating over your files, making both changes at once, writing to a temporary file and replacing the original on success, while having the value to be added as external variable:

v=9500
for f in *.json; do jq --argjson v $v '
  .edition += $v | .name |= ((./"#" | .[1] |= "\(tonumber + $v)") | join("#"))
' "$f" > "$f.new" && mv "$f.new" "$f"
done

Here is an online "playground for jq", set up to simulate the application of my code from above to three imaginary files of yours. Feel free to edit the jq filter and/or the input JSON in order to see what could be possible using jq.

pmf
  • 24,478
  • 2
  • 22
  • 31