0

I'm working on an automation script and I need to change the value in a config file. The config file that I'm trying to edit has a line like this (including the spaces before):

    "peer-port": 23456,

The 23456 might be any 5-digit number. The script that I'm writing will pass a new port that is stored in a variable called $newport. How can use a sed (or awk) command to replace "23456", (or whatever it is), with the new port value contained in the variable $newport?

A more-complete sample config file is:

{
    "alt-speed-down": 50, 
    "alt-speed-enabled": false, 
    "alt-speed-time-begin": 540, 
    "alt-speed-time-day": 127, 
    "alt-speed-time-enabled": false, 
    "alt-speed-time-end": 1020, 
    "alt-speed-up": 50, 
    "bind-address-ipv4": "0.0.0.0", 
    "bind-address-ipv6": "::", 
    "blocklist-enabled": false, 
    "blocklist-url": "http://www.example.com/blocklist", 
    "cache-size-mb": 2, 
    "dht-enabled": true, 
    "download-dir": "/var/media/orng/dl/", 
    "download-queue-enabled": true, 
    "download-queue-size": 1, 
    "encryption": 2, 
    "idle-seeding-limit": 30, 
    "idle-seeding-limit-enabled": false, 
    "incomplete-dir": "/var/media/orng/dl//incoming", 
    "incomplete-dir-enabled": true, 
    "lpd-enabled": false, 
    "message-level": 2, 
    "peer-congestion-algorithm": "", 
    "peer-limit-global": 100, 
    "peer-limit-per-torrent": 20, 
    "peer-port": 51413, 
    "peer-port-random-high": 65535, 
    "peer-port-random-low": 49152, 
    "peer-port-random-on-start": false, 
    "peer-socket-tos": "default", 
    "pex-enabled": true, 
    "port-forwarding-enabled": true, 
    "preallocation": 1, 
    "prefetch-enabled": 0, 
    "queue-stalled-enabled": true, 
    "queue-stalled-minutes": 30, 
    "ratio-limit": 0, 
    "ratio-limit-enabled": true, 
    "rename-partial-files": true, 
    "rpc-authentication-required": false, 
    "rpc-bind-address": "0.0.0.0", 
    "rpc-enabled": true, 
    "rpc-password": "{43041796ac49801e85577ba94a0e4ee5642d53a6soamZcAy", 
    "rpc-port": 9091, 
    "rpc-url": "/transmission/", 
    "rpc-username": "", 
    "rpc-whitelist": "127.0.0.1, 192.168.1.*", 
    "rpc-whitelist-enabled": true, 
    "scrape-paused-torrents-enabled": true, 
    "script-torrent-done-enabled": false, 
    "script-torrent-done-filename": "", 
    "seed-queue-enabled": false, 
    "seed-queue-size": 10, 
    "speed-limit-down": 100, 
    "speed-limit-down-enabled": false, 
    "speed-limit-up": 100, 
    "speed-limit-up-enabled": false, 
    "start-added-torrents": true, 
    "trash-original-torrent-files": false, 
    "umask": 18, 
    "upload-slots-per-torrent": 14, 
    "utp-enabled": true, 
    "watch-dir": "/var/media/orng/dl//watch", 
    "watch-dir-enabled": true
}
  • I’m running Ubuntu 18.04 and I’m not set on anything specific like sed or awk. Whatever is easiest. Here is a sample of the config file: gist.github.com/yyolk/4747010 – Shr00m Apr 21 at 0:04
  • jq should be available from the Ubuntu universe repository - in which case you should be able to use something like jq --argjson var "$newport" '."peer-port" = $var' settings.json I think – steeldriver Apr 21 at 1:43
1
jq --argjson port "$newport" '."peer-port" |= $port' file.json >file-new.json

This would produce a new file called file-new.json with the peer-port key's value changed to whatever the shell variable $newport is. The shell variable will be inserted as-is, i.e. without any encoding, so make sure it's a plain integer (using --arg instead of --argjson would insert it as an encoded string).

0

Try this test:

sed 's/^    "peer-port": [0-9]*,/    "peer-port": '"${newport}"',/' settings.json

...examine the output, and if it looks good, add an -i to actually change the file like so:

sed -i 's/^    "peer-port": [0-9]*,/    "peer-port": '"${newport}"',/' settings.json

Notes: the substitution strings may need a little tweaking, (i.e. replacing "" with "\t"), depending on whether the whitespace is spaces or tabs.

A more compact and efficient, (but maybe less portable), method:

sed `/^    "peer-port": /{s/ [0-9]*,/ '"${newport}",'/;q}' settings.json
  • I actually forgot to mention that the port will never be the same. The sed command needs to replace the old port (random 5 digit port) with one stored in $newport – Shr00m Apr 21 at 0:20
  • @Shr00m, See revised answer. – agc Apr 21 at 0:23
  • @agc instead of trying to guess what the leading whitespace is composed of (and the exact number of spaces or tabs) you should be able to use \s*? – Jeff H. Apr 21 at 0:38
  • 1
    Further suggestion to improve upon @agc answer, this is a little more concise: sed -i -E 's/^(\s*?"peer-port":\ )[0-9]{5},/\1'"$newport"'/' settings.json – Jeff H. Apr 21 at 0:50
  • @JeffH., Well maybe, but this is a novice question and \s is both harder to explain and not always intuitive. Consider the output of this code echo foo | sed 's/\s*/\t/'; there's no visible leading whitespace in the input, but there is in the output... Also it's uncertain whether or not the OP is running GNU sed; if not then stuff like [0-9]{5} won't work. The lead ^ is an improvement in any case though. – agc Apr 21 at 0:52
0

Generally, you do not need the whole string to make a pattern for a sed search string, you just need a unique part of it, and "(peer-port.+) ([0-9]+)" looks perfectly sufficient for the case, sort of find the keyword with a little tail for it then then sequence of digits and replace all that with first thing unchanged(\1) and second thing using the string in a script.

#!/bin/bash

FNAME=$1
NPORT=$2
SSTR='{s/(peer-port.+) ([0-9]+)/\1 '$NPORT'/};'
echo "new port $NPORT in $FNAME"

sed -E -i -e "$SSTR" $FNAME
0

Parsing nested data formats (like json) must be done with respective (json format aware) utilities. sed is a line only aware. Here's an easy solution based on walk-path unix utility jtc:

bash $ newport=12345
bash $ jtc -w[peer-port] -u"$newport" -f file.json 
bash $ jtc -w[peer-port] file.json 
12345
bash $ 

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.