Reshaping json / reparing json inside shell script (remove trailing comma) The Next CEO of Stack Overflowfind statement inside backticks not recognised inside shell scriptRemove lines in a shell scriptWrite permissions inside shell scriptShell script taking me inside the serversource inside a shell scriptReplace the comma with vertical bar |, except when inside double quotes, and remove double quotesRemoval of double quotes and substitution of comma inside itlooping through JSON array in shell scriptshell script inside dockerUse line break in JSON inside a shell script

Is it correct to say moon starry nights?

What difference does it make using sed with/without whitespaces?

What does "shotgun unity" refer to here in this sentence?

Towers in the ocean; How deep can they be built?

Is there a way to save my career from absolute disaster?

Is a distribution that is normal, but highly skewed, considered Gaussian?

Strange use of "whether ... than ..." in official text

Expressing the idea of having a very busy time

Spaces in which all closed sets are regular closed

Is French Guiana a (hard) EU border?

Players Circumventing the limitations of Wish

What is the difference between Statistical Mechanics and Quantum Mechanics

Is it convenient to ask the journal's editor for two additional days to complete a review?

Yu-Gi-Oh cards in Python 3

What CSS properties can the br tag have?

Easy to read palindrome checker

Purpose of level-shifter with same in and out voltages

Lucky Feat: How can "more than one creature spend a luck point to influence the outcome of a roll"?

If Nick Fury and Coulson already knew about aliens (Kree and Skrull) why did they wait until Thor's appearance to start making weapons?

Prepend last line of stdin to entire stdin

Does destroying a Lich's phylactery destroy the soul within it?

How many extra stops do monopods offer for tele photographs?

When "be it" is at the beginning of a sentence, what kind of structure do you call it?

Audio Conversion With ADS1243



Reshaping json / reparing json inside shell script (remove trailing comma)



The Next CEO of Stack Overflowfind statement inside backticks not recognised inside shell scriptRemove lines in a shell scriptWrite permissions inside shell scriptShell script taking me inside the serversource inside a shell scriptReplace the comma with vertical bar |, except when inside double quotes, and remove double quotesRemoval of double quotes and substitution of comma inside itlooping through JSON array in shell scriptshell script inside dockerUse line break in JSON inside a shell script










2















I've googled around a lot for this and it seems there is no precursor to this need.



I need to edit an applications preference file programatically : as part of a shell script.



and the prefs are stored in strict json format : this means the app loading that preference file will crash at startup if there is a comma , before a closing curly brace }.



normally this wouldn't be an issue.



I'd just use my seds accordingly : if the line containing my faulty text lines up at the end of a section in my example file, then when replacing this text I will always put it without a comma.



If another line containing another faulty bit I want to replace is not at the end, I always replace it including a comma.



Example :



(I use underscore _ as my sed's delimiter because the stings to replace are full of backslashes sometimes)



sed -i 's_"executableDecorator".*_"executableDecorator": "'$user_path'/faf/run \"%s\"",_' $user_path/.faforever/client.prefs


if that line was at the end :



sed -i 's_"executableDecorator".*_"executableDecorator": "'$user_path'/faf/run \"%s\""_' $user_path/.faforever/client.prefs


this would work, But!...



I have the app end before I run my script so that both aren't editing the preferences at the same time, but even still, because of this app's asynchronous execution the preferences my script will be receiving will differ every time.



it's completely random.



sometimes a line could be in the middle sometimes at the end. The app itself (Java & some json java lib) knows how to append comma or not depending on the context but as part of my shell script... I feel things are going to get bloated.



(If not and there's a shorthand to ensure I have comma or not depending on if next line is }, then that is a better simpler solution that I would be more interested in)



But as it stands I'm looking for a POSIX utility that fixes json so that I can "sanitize" my json prefs file as soon as I'm done butchering it all within my shell script ...does such a thing exist?



EDIT :



here's the base file (whole file, ) :




"mainWindow":
"width": 800,
"height": 600,
"maximized": false,
"lastView": "NEWS",
"lastChildViews": ,
"x": 67.0,
"y": 27.0
,
"forgedAlliance":
"customMapsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Maps",
"preferencesFile": "/home/t/.wine/drive_c/users/t/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",
"officialMapsDirectory": "/home/t/faf/./Maps",
"modsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Mods",
"port": 6112,
"autoDownloadMaps": true,
"executableDecorator": ""%s""
,
"login":
"username": "tatsu",
"password": "*******",
"autoLogin": true
,
"chat":
"zoom": 1.0,
"learnedAutoComplete": false,
"previewImageUrls": true,
"maxMessages": 500,
"chatColorMode": "CUSTOM",
"channelTabScrollPaneWidth": 250,
"userToColor": ,
"hideFoeMessages": true,
"timeFormat": "AUTO",
"chatFormat": "COMPACT",
"idleThreshold": 10
,
"notification":
"soundsEnabled": true,
"transientNotificationsEnabled": true,
"mentionSoundEnabled": true,
"infoSoundEnabled": true,
"warnSoundEnabled": true,
"errorSoundEnabled": true,
"friendOnlineToastEnabled": true,
"friendOfflineToastEnabled": true,
"ladder1v1ToastEnabled": true,
"friendOnlineSoundEnabled": true,
"friendOfflineSoundEnabled": true,
"friendJoinsGameSoundEnabled": true,
"friendPlaysGameSoundEnabled": true,
"friendPlaysGameToastEnabled": true,
"privateMessageSoundEnabled": true,
"privateMessageToastEnabled": true,
"friendJoinsGameToastEnabled": true,
"notifyOnAtMentionOnlyEnabled": false,
"afterGameReviewEnabled": true,
"toastPosition": "BOTTOM_RIGHT",
"toastScreen": 0,
"toastDisplayTime": 5000
,
"themeName": "default",
"lastGameType": "faf",
"localization": ,
"rememberLastTab": true,
"showPasswordProtectedGames": true,
"showModdedGames": true,
"ignoredNotifications": [],
"lastGameMinRating": 800,
"lastGameMaxRating": 1300,
"ladder1v1":
"factions": [
"aeon",
"cybran",
"uef",
"seraphim"
]
,
"news":
"lastReadNewsUrl": "http://direct.faforever.com/2019/03/king-of-badlands-tournament-march-30th/"
,
"developer":
"gameRepositoryUrl": "https://github.com/FAForever/fa.git"
,
"vaultPrefs":
"onlineReplaySortConfig":
"sortProperty": "startTime",
"sortOrder": "DESC"
,
"mapSortConfig":
"sortProperty": "statistics.plays",
"sortOrder": "DESC"
,
"modVaultConfig":
"sortProperty": "latestVersion.createTime",
"sortOrder": "DESC"

,
"gameListSorting": [],
"gameTileSortingOrder": "PLAYER_DES",
"unitDataBaseType": "RACKOVER",
"storedCookies": ,
"lastGameOnlyFriends": false



the only part that matters is "forgedAlliance" :



 "forgedAlliance": 
"customMapsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Maps",
"preferencesFile": "/home/t/.wine/drive_c/users/t/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",
"officialMapsDirectory": "/home/t/faf/./Maps",
"modsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Mods",
"port": 6112,
"autoDownloadMaps": true,
"executableDecorator": ""%s""
,


I run commands to obtain this :



 "forgedAlliance": 
"path": "/home/t/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",
"installationPath": "/home/t/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",
"customMapsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Maps",
"preferencesFile": "/home/t/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",
"officialMapsDirectory": "/home/t/faf/./Maps",
"modsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Mods",
"port": 6112,
"autoDownloadMaps": true,
"executableDecorator": "/home/t/faf/run "%s""
,


the commands that work (in a standard case where things don't move around) are :



if ! grep -q '"path"' $user_path/.faforever/client.prefs > /dev/null
then
sed -i '12i"path": "'$user_path'/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",' $user_path/.faforever/client.prefs
sed -i '13i"installationPath": "'$user_path'/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",' $user_path/.faforever/client.prefs
fi
! grep -q '"preferencesFile": "'$user_path'/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",' $user_path/.faforever/client.prefs > /dev/null && sed -i 's_"preferencesFile".*_"preferencesFile": "'$user_path'/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",_' $user_path/.faforever/client.prefs
! grep -q '"executableDecorator": "'$user_path'/faf/",' $user_path/.faforever/client.prefs > /dev/null && sed -i 's_"executableDecorator".*_"executableDecorator": "'$user_path'/faf/run \"%s\""_' $user_path/.faforever/client.prefs









share|improve this question
























  • Is there no way at all you could use jq or similar to modify it in the first place instead of text-mangling?

    – Michael Homer
    3 hours ago











  • surely! what's jq? googling...

    – tatsu
    3 hours ago











  • In that case, if you could provide a minimal example of the file structure and the changes you'd like to make, someone can probably steer you right.

    – Michael Homer
    3 hours ago











  • Ok, I added the file, plus the bit I edit, plus the result and also what I used to get there.

    – tatsu
    3 hours ago















2















I've googled around a lot for this and it seems there is no precursor to this need.



I need to edit an applications preference file programatically : as part of a shell script.



and the prefs are stored in strict json format : this means the app loading that preference file will crash at startup if there is a comma , before a closing curly brace }.



normally this wouldn't be an issue.



I'd just use my seds accordingly : if the line containing my faulty text lines up at the end of a section in my example file, then when replacing this text I will always put it without a comma.



If another line containing another faulty bit I want to replace is not at the end, I always replace it including a comma.



Example :



(I use underscore _ as my sed's delimiter because the stings to replace are full of backslashes sometimes)



sed -i 's_"executableDecorator".*_"executableDecorator": "'$user_path'/faf/run \"%s\"",_' $user_path/.faforever/client.prefs


if that line was at the end :



sed -i 's_"executableDecorator".*_"executableDecorator": "'$user_path'/faf/run \"%s\""_' $user_path/.faforever/client.prefs


this would work, But!...



I have the app end before I run my script so that both aren't editing the preferences at the same time, but even still, because of this app's asynchronous execution the preferences my script will be receiving will differ every time.



it's completely random.



sometimes a line could be in the middle sometimes at the end. The app itself (Java & some json java lib) knows how to append comma or not depending on the context but as part of my shell script... I feel things are going to get bloated.



(If not and there's a shorthand to ensure I have comma or not depending on if next line is }, then that is a better simpler solution that I would be more interested in)



But as it stands I'm looking for a POSIX utility that fixes json so that I can "sanitize" my json prefs file as soon as I'm done butchering it all within my shell script ...does such a thing exist?



EDIT :



here's the base file (whole file, ) :




"mainWindow":
"width": 800,
"height": 600,
"maximized": false,
"lastView": "NEWS",
"lastChildViews": ,
"x": 67.0,
"y": 27.0
,
"forgedAlliance":
"customMapsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Maps",
"preferencesFile": "/home/t/.wine/drive_c/users/t/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",
"officialMapsDirectory": "/home/t/faf/./Maps",
"modsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Mods",
"port": 6112,
"autoDownloadMaps": true,
"executableDecorator": ""%s""
,
"login":
"username": "tatsu",
"password": "*******",
"autoLogin": true
,
"chat":
"zoom": 1.0,
"learnedAutoComplete": false,
"previewImageUrls": true,
"maxMessages": 500,
"chatColorMode": "CUSTOM",
"channelTabScrollPaneWidth": 250,
"userToColor": ,
"hideFoeMessages": true,
"timeFormat": "AUTO",
"chatFormat": "COMPACT",
"idleThreshold": 10
,
"notification":
"soundsEnabled": true,
"transientNotificationsEnabled": true,
"mentionSoundEnabled": true,
"infoSoundEnabled": true,
"warnSoundEnabled": true,
"errorSoundEnabled": true,
"friendOnlineToastEnabled": true,
"friendOfflineToastEnabled": true,
"ladder1v1ToastEnabled": true,
"friendOnlineSoundEnabled": true,
"friendOfflineSoundEnabled": true,
"friendJoinsGameSoundEnabled": true,
"friendPlaysGameSoundEnabled": true,
"friendPlaysGameToastEnabled": true,
"privateMessageSoundEnabled": true,
"privateMessageToastEnabled": true,
"friendJoinsGameToastEnabled": true,
"notifyOnAtMentionOnlyEnabled": false,
"afterGameReviewEnabled": true,
"toastPosition": "BOTTOM_RIGHT",
"toastScreen": 0,
"toastDisplayTime": 5000
,
"themeName": "default",
"lastGameType": "faf",
"localization": ,
"rememberLastTab": true,
"showPasswordProtectedGames": true,
"showModdedGames": true,
"ignoredNotifications": [],
"lastGameMinRating": 800,
"lastGameMaxRating": 1300,
"ladder1v1":
"factions": [
"aeon",
"cybran",
"uef",
"seraphim"
]
,
"news":
"lastReadNewsUrl": "http://direct.faforever.com/2019/03/king-of-badlands-tournament-march-30th/"
,
"developer":
"gameRepositoryUrl": "https://github.com/FAForever/fa.git"
,
"vaultPrefs":
"onlineReplaySortConfig":
"sortProperty": "startTime",
"sortOrder": "DESC"
,
"mapSortConfig":
"sortProperty": "statistics.plays",
"sortOrder": "DESC"
,
"modVaultConfig":
"sortProperty": "latestVersion.createTime",
"sortOrder": "DESC"

,
"gameListSorting": [],
"gameTileSortingOrder": "PLAYER_DES",
"unitDataBaseType": "RACKOVER",
"storedCookies": ,
"lastGameOnlyFriends": false



the only part that matters is "forgedAlliance" :



 "forgedAlliance": 
"customMapsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Maps",
"preferencesFile": "/home/t/.wine/drive_c/users/t/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",
"officialMapsDirectory": "/home/t/faf/./Maps",
"modsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Mods",
"port": 6112,
"autoDownloadMaps": true,
"executableDecorator": ""%s""
,


I run commands to obtain this :



 "forgedAlliance": 
"path": "/home/t/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",
"installationPath": "/home/t/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",
"customMapsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Maps",
"preferencesFile": "/home/t/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",
"officialMapsDirectory": "/home/t/faf/./Maps",
"modsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Mods",
"port": 6112,
"autoDownloadMaps": true,
"executableDecorator": "/home/t/faf/run "%s""
,


the commands that work (in a standard case where things don't move around) are :



if ! grep -q '"path"' $user_path/.faforever/client.prefs > /dev/null
then
sed -i '12i"path": "'$user_path'/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",' $user_path/.faforever/client.prefs
sed -i '13i"installationPath": "'$user_path'/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",' $user_path/.faforever/client.prefs
fi
! grep -q '"preferencesFile": "'$user_path'/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",' $user_path/.faforever/client.prefs > /dev/null && sed -i 's_"preferencesFile".*_"preferencesFile": "'$user_path'/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",_' $user_path/.faforever/client.prefs
! grep -q '"executableDecorator": "'$user_path'/faf/",' $user_path/.faforever/client.prefs > /dev/null && sed -i 's_"executableDecorator".*_"executableDecorator": "'$user_path'/faf/run \"%s\""_' $user_path/.faforever/client.prefs









share|improve this question
























  • Is there no way at all you could use jq or similar to modify it in the first place instead of text-mangling?

    – Michael Homer
    3 hours ago











  • surely! what's jq? googling...

    – tatsu
    3 hours ago











  • In that case, if you could provide a minimal example of the file structure and the changes you'd like to make, someone can probably steer you right.

    – Michael Homer
    3 hours ago











  • Ok, I added the file, plus the bit I edit, plus the result and also what I used to get there.

    – tatsu
    3 hours ago













2












2








2








I've googled around a lot for this and it seems there is no precursor to this need.



I need to edit an applications preference file programatically : as part of a shell script.



and the prefs are stored in strict json format : this means the app loading that preference file will crash at startup if there is a comma , before a closing curly brace }.



normally this wouldn't be an issue.



I'd just use my seds accordingly : if the line containing my faulty text lines up at the end of a section in my example file, then when replacing this text I will always put it without a comma.



If another line containing another faulty bit I want to replace is not at the end, I always replace it including a comma.



Example :



(I use underscore _ as my sed's delimiter because the stings to replace are full of backslashes sometimes)



sed -i 's_"executableDecorator".*_"executableDecorator": "'$user_path'/faf/run \"%s\"",_' $user_path/.faforever/client.prefs


if that line was at the end :



sed -i 's_"executableDecorator".*_"executableDecorator": "'$user_path'/faf/run \"%s\""_' $user_path/.faforever/client.prefs


this would work, But!...



I have the app end before I run my script so that both aren't editing the preferences at the same time, but even still, because of this app's asynchronous execution the preferences my script will be receiving will differ every time.



it's completely random.



sometimes a line could be in the middle sometimes at the end. The app itself (Java & some json java lib) knows how to append comma or not depending on the context but as part of my shell script... I feel things are going to get bloated.



(If not and there's a shorthand to ensure I have comma or not depending on if next line is }, then that is a better simpler solution that I would be more interested in)



But as it stands I'm looking for a POSIX utility that fixes json so that I can "sanitize" my json prefs file as soon as I'm done butchering it all within my shell script ...does such a thing exist?



EDIT :



here's the base file (whole file, ) :




"mainWindow":
"width": 800,
"height": 600,
"maximized": false,
"lastView": "NEWS",
"lastChildViews": ,
"x": 67.0,
"y": 27.0
,
"forgedAlliance":
"customMapsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Maps",
"preferencesFile": "/home/t/.wine/drive_c/users/t/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",
"officialMapsDirectory": "/home/t/faf/./Maps",
"modsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Mods",
"port": 6112,
"autoDownloadMaps": true,
"executableDecorator": ""%s""
,
"login":
"username": "tatsu",
"password": "*******",
"autoLogin": true
,
"chat":
"zoom": 1.0,
"learnedAutoComplete": false,
"previewImageUrls": true,
"maxMessages": 500,
"chatColorMode": "CUSTOM",
"channelTabScrollPaneWidth": 250,
"userToColor": ,
"hideFoeMessages": true,
"timeFormat": "AUTO",
"chatFormat": "COMPACT",
"idleThreshold": 10
,
"notification":
"soundsEnabled": true,
"transientNotificationsEnabled": true,
"mentionSoundEnabled": true,
"infoSoundEnabled": true,
"warnSoundEnabled": true,
"errorSoundEnabled": true,
"friendOnlineToastEnabled": true,
"friendOfflineToastEnabled": true,
"ladder1v1ToastEnabled": true,
"friendOnlineSoundEnabled": true,
"friendOfflineSoundEnabled": true,
"friendJoinsGameSoundEnabled": true,
"friendPlaysGameSoundEnabled": true,
"friendPlaysGameToastEnabled": true,
"privateMessageSoundEnabled": true,
"privateMessageToastEnabled": true,
"friendJoinsGameToastEnabled": true,
"notifyOnAtMentionOnlyEnabled": false,
"afterGameReviewEnabled": true,
"toastPosition": "BOTTOM_RIGHT",
"toastScreen": 0,
"toastDisplayTime": 5000
,
"themeName": "default",
"lastGameType": "faf",
"localization": ,
"rememberLastTab": true,
"showPasswordProtectedGames": true,
"showModdedGames": true,
"ignoredNotifications": [],
"lastGameMinRating": 800,
"lastGameMaxRating": 1300,
"ladder1v1":
"factions": [
"aeon",
"cybran",
"uef",
"seraphim"
]
,
"news":
"lastReadNewsUrl": "http://direct.faforever.com/2019/03/king-of-badlands-tournament-march-30th/"
,
"developer":
"gameRepositoryUrl": "https://github.com/FAForever/fa.git"
,
"vaultPrefs":
"onlineReplaySortConfig":
"sortProperty": "startTime",
"sortOrder": "DESC"
,
"mapSortConfig":
"sortProperty": "statistics.plays",
"sortOrder": "DESC"
,
"modVaultConfig":
"sortProperty": "latestVersion.createTime",
"sortOrder": "DESC"

,
"gameListSorting": [],
"gameTileSortingOrder": "PLAYER_DES",
"unitDataBaseType": "RACKOVER",
"storedCookies": ,
"lastGameOnlyFriends": false



the only part that matters is "forgedAlliance" :



 "forgedAlliance": 
"customMapsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Maps",
"preferencesFile": "/home/t/.wine/drive_c/users/t/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",
"officialMapsDirectory": "/home/t/faf/./Maps",
"modsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Mods",
"port": 6112,
"autoDownloadMaps": true,
"executableDecorator": ""%s""
,


I run commands to obtain this :



 "forgedAlliance": 
"path": "/home/t/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",
"installationPath": "/home/t/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",
"customMapsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Maps",
"preferencesFile": "/home/t/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",
"officialMapsDirectory": "/home/t/faf/./Maps",
"modsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Mods",
"port": 6112,
"autoDownloadMaps": true,
"executableDecorator": "/home/t/faf/run "%s""
,


the commands that work (in a standard case where things don't move around) are :



if ! grep -q '"path"' $user_path/.faforever/client.prefs > /dev/null
then
sed -i '12i"path": "'$user_path'/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",' $user_path/.faforever/client.prefs
sed -i '13i"installationPath": "'$user_path'/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",' $user_path/.faforever/client.prefs
fi
! grep -q '"preferencesFile": "'$user_path'/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",' $user_path/.faforever/client.prefs > /dev/null && sed -i 's_"preferencesFile".*_"preferencesFile": "'$user_path'/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",_' $user_path/.faforever/client.prefs
! grep -q '"executableDecorator": "'$user_path'/faf/",' $user_path/.faforever/client.prefs > /dev/null && sed -i 's_"executableDecorator".*_"executableDecorator": "'$user_path'/faf/run \"%s\""_' $user_path/.faforever/client.prefs









share|improve this question
















I've googled around a lot for this and it seems there is no precursor to this need.



I need to edit an applications preference file programatically : as part of a shell script.



and the prefs are stored in strict json format : this means the app loading that preference file will crash at startup if there is a comma , before a closing curly brace }.



normally this wouldn't be an issue.



I'd just use my seds accordingly : if the line containing my faulty text lines up at the end of a section in my example file, then when replacing this text I will always put it without a comma.



If another line containing another faulty bit I want to replace is not at the end, I always replace it including a comma.



Example :



(I use underscore _ as my sed's delimiter because the stings to replace are full of backslashes sometimes)



sed -i 's_"executableDecorator".*_"executableDecorator": "'$user_path'/faf/run \"%s\"",_' $user_path/.faforever/client.prefs


if that line was at the end :



sed -i 's_"executableDecorator".*_"executableDecorator": "'$user_path'/faf/run \"%s\""_' $user_path/.faforever/client.prefs


this would work, But!...



I have the app end before I run my script so that both aren't editing the preferences at the same time, but even still, because of this app's asynchronous execution the preferences my script will be receiving will differ every time.



it's completely random.



sometimes a line could be in the middle sometimes at the end. The app itself (Java & some json java lib) knows how to append comma or not depending on the context but as part of my shell script... I feel things are going to get bloated.



(If not and there's a shorthand to ensure I have comma or not depending on if next line is }, then that is a better simpler solution that I would be more interested in)



But as it stands I'm looking for a POSIX utility that fixes json so that I can "sanitize" my json prefs file as soon as I'm done butchering it all within my shell script ...does such a thing exist?



EDIT :



here's the base file (whole file, ) :




"mainWindow":
"width": 800,
"height": 600,
"maximized": false,
"lastView": "NEWS",
"lastChildViews": ,
"x": 67.0,
"y": 27.0
,
"forgedAlliance":
"customMapsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Maps",
"preferencesFile": "/home/t/.wine/drive_c/users/t/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",
"officialMapsDirectory": "/home/t/faf/./Maps",
"modsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Mods",
"port": 6112,
"autoDownloadMaps": true,
"executableDecorator": ""%s""
,
"login":
"username": "tatsu",
"password": "*******",
"autoLogin": true
,
"chat":
"zoom": 1.0,
"learnedAutoComplete": false,
"previewImageUrls": true,
"maxMessages": 500,
"chatColorMode": "CUSTOM",
"channelTabScrollPaneWidth": 250,
"userToColor": ,
"hideFoeMessages": true,
"timeFormat": "AUTO",
"chatFormat": "COMPACT",
"idleThreshold": 10
,
"notification":
"soundsEnabled": true,
"transientNotificationsEnabled": true,
"mentionSoundEnabled": true,
"infoSoundEnabled": true,
"warnSoundEnabled": true,
"errorSoundEnabled": true,
"friendOnlineToastEnabled": true,
"friendOfflineToastEnabled": true,
"ladder1v1ToastEnabled": true,
"friendOnlineSoundEnabled": true,
"friendOfflineSoundEnabled": true,
"friendJoinsGameSoundEnabled": true,
"friendPlaysGameSoundEnabled": true,
"friendPlaysGameToastEnabled": true,
"privateMessageSoundEnabled": true,
"privateMessageToastEnabled": true,
"friendJoinsGameToastEnabled": true,
"notifyOnAtMentionOnlyEnabled": false,
"afterGameReviewEnabled": true,
"toastPosition": "BOTTOM_RIGHT",
"toastScreen": 0,
"toastDisplayTime": 5000
,
"themeName": "default",
"lastGameType": "faf",
"localization": ,
"rememberLastTab": true,
"showPasswordProtectedGames": true,
"showModdedGames": true,
"ignoredNotifications": [],
"lastGameMinRating": 800,
"lastGameMaxRating": 1300,
"ladder1v1":
"factions": [
"aeon",
"cybran",
"uef",
"seraphim"
]
,
"news":
"lastReadNewsUrl": "http://direct.faforever.com/2019/03/king-of-badlands-tournament-march-30th/"
,
"developer":
"gameRepositoryUrl": "https://github.com/FAForever/fa.git"
,
"vaultPrefs":
"onlineReplaySortConfig":
"sortProperty": "startTime",
"sortOrder": "DESC"
,
"mapSortConfig":
"sortProperty": "statistics.plays",
"sortOrder": "DESC"
,
"modVaultConfig":
"sortProperty": "latestVersion.createTime",
"sortOrder": "DESC"

,
"gameListSorting": [],
"gameTileSortingOrder": "PLAYER_DES",
"unitDataBaseType": "RACKOVER",
"storedCookies": ,
"lastGameOnlyFriends": false



the only part that matters is "forgedAlliance" :



 "forgedAlliance": 
"customMapsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Maps",
"preferencesFile": "/home/t/.wine/drive_c/users/t/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",
"officialMapsDirectory": "/home/t/faf/./Maps",
"modsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Mods",
"port": 6112,
"autoDownloadMaps": true,
"executableDecorator": ""%s""
,


I run commands to obtain this :



 "forgedAlliance": 
"path": "/home/t/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",
"installationPath": "/home/t/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",
"customMapsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Maps",
"preferencesFile": "/home/t/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",
"officialMapsDirectory": "/home/t/faf/./Maps",
"modsDirectory": "/home/t/My Games/Gas Powered Games/Supreme Commander Forged Alliance/Mods",
"port": 6112,
"autoDownloadMaps": true,
"executableDecorator": "/home/t/faf/run "%s""
,


the commands that work (in a standard case where things don't move around) are :



if ! grep -q '"path"' $user_path/.faforever/client.prefs > /dev/null
then
sed -i '12i"path": "'$user_path'/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",' $user_path/.faforever/client.prefs
sed -i '13i"installationPath": "'$user_path'/.steam/steam/steamapps/common/Supreme Commander Forged Alliance",' $user_path/.faforever/client.prefs
fi
! grep -q '"preferencesFile": "'$user_path'/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",' $user_path/.faforever/client.prefs > /dev/null && sed -i 's_"preferencesFile".*_"preferencesFile": "'$user_path'/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs",_' $user_path/.faforever/client.prefs
! grep -q '"executableDecorator": "'$user_path'/faf/",' $user_path/.faforever/client.prefs > /dev/null && sed -i 's_"executableDecorator".*_"executableDecorator": "'$user_path'/faf/run \"%s\""_' $user_path/.faforever/client.prefs






shell-script shell sed posix






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 3 hours ago







tatsu

















asked 3 hours ago









tatsutatsu

1137




1137












  • Is there no way at all you could use jq or similar to modify it in the first place instead of text-mangling?

    – Michael Homer
    3 hours ago











  • surely! what's jq? googling...

    – tatsu
    3 hours ago











  • In that case, if you could provide a minimal example of the file structure and the changes you'd like to make, someone can probably steer you right.

    – Michael Homer
    3 hours ago











  • Ok, I added the file, plus the bit I edit, plus the result and also what I used to get there.

    – tatsu
    3 hours ago

















  • Is there no way at all you could use jq or similar to modify it in the first place instead of text-mangling?

    – Michael Homer
    3 hours ago











  • surely! what's jq? googling...

    – tatsu
    3 hours ago











  • In that case, if you could provide a minimal example of the file structure and the changes you'd like to make, someone can probably steer you right.

    – Michael Homer
    3 hours ago











  • Ok, I added the file, plus the bit I edit, plus the result and also what I used to get there.

    – tatsu
    3 hours ago
















Is there no way at all you could use jq or similar to modify it in the first place instead of text-mangling?

– Michael Homer
3 hours ago





Is there no way at all you could use jq or similar to modify it in the first place instead of text-mangling?

– Michael Homer
3 hours ago













surely! what's jq? googling...

– tatsu
3 hours ago





surely! what's jq? googling...

– tatsu
3 hours ago













In that case, if you could provide a minimal example of the file structure and the changes you'd like to make, someone can probably steer you right.

– Michael Homer
3 hours ago





In that case, if you could provide a minimal example of the file structure and the changes you'd like to make, someone can probably steer you right.

– Michael Homer
3 hours ago













Ok, I added the file, plus the bit I edit, plus the result and also what I used to get there.

– tatsu
3 hours ago





Ok, I added the file, plus the bit I edit, plus the result and also what I used to get there.

– tatsu
3 hours ago










1 Answer
1






active

oldest

votes


















4














This jq command will make exactly those changes:



jq --arg user_path "$user_path" '
.forgedAlliance +=
installationPath: ($user_path + "/.steam/steam/steamapps/common/Supreme Commander Forged Alliance"),
path: ($user_path + "/.steam/steam/steamapps/common/Supreme Commander Forged Alliance"),
preferencesFile: ($user_path + "/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs"),
executableDecorator: ($user_path + "/faf/run "%s"")
'


This uses




  1. --arg user_path "$user_path" to bring the shell variable into the jq program (you could also use the variable binding operator "'"$user_path"'" as $user_path |, but it would involve ugly quote splicing)

  2. Update-assignment .forgedAlliance += to process the whole file, updating just the value of the "forgedAlliance" key by merging it with what's on the right.

  3. A fresh object constructed from to with just the new key values you wanted computed inside it. If there are existing keys with the same name, they will be replaced.


  4. $user_path to access that variable binding we made above.

The whitespace is optional - it's just there to make it easier to read on this site.



jq always outputs as valid JSON, so you don't have any comma cleanup to do. You may find the sponge command from moreutils useful for updating the file itself, because there is no -i equivalent in jq, but you can also just redirect to another file



jq ... > tmpfile
mv tmpfile prefs.json


and step around it manually as well.



There is one (slight?) difference to what your code did: you made no changes for path and installationPath if "path" appeared anywhere in the file. There's no way to replicate that with jq directly, but you could split the command in two (one for path, one for all the time) if there's a necessary semantic element to that. This command will always make the change, but if it's already got the same value for a key that doesn't have any effect.




If this is a fixed set of replacements, you could also make a file with just the object from point 3 above in it literally (as true JSON, not dynamically computed), and then use



jq --slurpfile tmp rhs.json '.forgedAlliance += tmp[0]'


with the same effect as the big command above.






share|improve this answer























  • "you made no changes for path and installationPath if "path" appeared anywhere in the file.", well looking back on that that's terrible. I prefer your approach. it does mean installing jq will have to become part of the script but maybe that's a manageable sacrifice.

    – tatsu
    45 mins ago












Your Answer








StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f509764%2freshaping-json-reparing-json-inside-shell-script-remove-trailing-comma%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









4














This jq command will make exactly those changes:



jq --arg user_path "$user_path" '
.forgedAlliance +=
installationPath: ($user_path + "/.steam/steam/steamapps/common/Supreme Commander Forged Alliance"),
path: ($user_path + "/.steam/steam/steamapps/common/Supreme Commander Forged Alliance"),
preferencesFile: ($user_path + "/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs"),
executableDecorator: ($user_path + "/faf/run "%s"")
'


This uses




  1. --arg user_path "$user_path" to bring the shell variable into the jq program (you could also use the variable binding operator "'"$user_path"'" as $user_path |, but it would involve ugly quote splicing)

  2. Update-assignment .forgedAlliance += to process the whole file, updating just the value of the "forgedAlliance" key by merging it with what's on the right.

  3. A fresh object constructed from to with just the new key values you wanted computed inside it. If there are existing keys with the same name, they will be replaced.


  4. $user_path to access that variable binding we made above.

The whitespace is optional - it's just there to make it easier to read on this site.



jq always outputs as valid JSON, so you don't have any comma cleanup to do. You may find the sponge command from moreutils useful for updating the file itself, because there is no -i equivalent in jq, but you can also just redirect to another file



jq ... > tmpfile
mv tmpfile prefs.json


and step around it manually as well.



There is one (slight?) difference to what your code did: you made no changes for path and installationPath if "path" appeared anywhere in the file. There's no way to replicate that with jq directly, but you could split the command in two (one for path, one for all the time) if there's a necessary semantic element to that. This command will always make the change, but if it's already got the same value for a key that doesn't have any effect.




If this is a fixed set of replacements, you could also make a file with just the object from point 3 above in it literally (as true JSON, not dynamically computed), and then use



jq --slurpfile tmp rhs.json '.forgedAlliance += tmp[0]'


with the same effect as the big command above.






share|improve this answer























  • "you made no changes for path and installationPath if "path" appeared anywhere in the file.", well looking back on that that's terrible. I prefer your approach. it does mean installing jq will have to become part of the script but maybe that's a manageable sacrifice.

    – tatsu
    45 mins ago
















4














This jq command will make exactly those changes:



jq --arg user_path "$user_path" '
.forgedAlliance +=
installationPath: ($user_path + "/.steam/steam/steamapps/common/Supreme Commander Forged Alliance"),
path: ($user_path + "/.steam/steam/steamapps/common/Supreme Commander Forged Alliance"),
preferencesFile: ($user_path + "/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs"),
executableDecorator: ($user_path + "/faf/run "%s"")
'


This uses




  1. --arg user_path "$user_path" to bring the shell variable into the jq program (you could also use the variable binding operator "'"$user_path"'" as $user_path |, but it would involve ugly quote splicing)

  2. Update-assignment .forgedAlliance += to process the whole file, updating just the value of the "forgedAlliance" key by merging it with what's on the right.

  3. A fresh object constructed from to with just the new key values you wanted computed inside it. If there are existing keys with the same name, they will be replaced.


  4. $user_path to access that variable binding we made above.

The whitespace is optional - it's just there to make it easier to read on this site.



jq always outputs as valid JSON, so you don't have any comma cleanup to do. You may find the sponge command from moreutils useful for updating the file itself, because there is no -i equivalent in jq, but you can also just redirect to another file



jq ... > tmpfile
mv tmpfile prefs.json


and step around it manually as well.



There is one (slight?) difference to what your code did: you made no changes for path and installationPath if "path" appeared anywhere in the file. There's no way to replicate that with jq directly, but you could split the command in two (one for path, one for all the time) if there's a necessary semantic element to that. This command will always make the change, but if it's already got the same value for a key that doesn't have any effect.




If this is a fixed set of replacements, you could also make a file with just the object from point 3 above in it literally (as true JSON, not dynamically computed), and then use



jq --slurpfile tmp rhs.json '.forgedAlliance += tmp[0]'


with the same effect as the big command above.






share|improve this answer























  • "you made no changes for path and installationPath if "path" appeared anywhere in the file.", well looking back on that that's terrible. I prefer your approach. it does mean installing jq will have to become part of the script but maybe that's a manageable sacrifice.

    – tatsu
    45 mins ago














4












4








4







This jq command will make exactly those changes:



jq --arg user_path "$user_path" '
.forgedAlliance +=
installationPath: ($user_path + "/.steam/steam/steamapps/common/Supreme Commander Forged Alliance"),
path: ($user_path + "/.steam/steam/steamapps/common/Supreme Commander Forged Alliance"),
preferencesFile: ($user_path + "/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs"),
executableDecorator: ($user_path + "/faf/run "%s"")
'


This uses




  1. --arg user_path "$user_path" to bring the shell variable into the jq program (you could also use the variable binding operator "'"$user_path"'" as $user_path |, but it would involve ugly quote splicing)

  2. Update-assignment .forgedAlliance += to process the whole file, updating just the value of the "forgedAlliance" key by merging it with what's on the right.

  3. A fresh object constructed from to with just the new key values you wanted computed inside it. If there are existing keys with the same name, they will be replaced.


  4. $user_path to access that variable binding we made above.

The whitespace is optional - it's just there to make it easier to read on this site.



jq always outputs as valid JSON, so you don't have any comma cleanup to do. You may find the sponge command from moreutils useful for updating the file itself, because there is no -i equivalent in jq, but you can also just redirect to another file



jq ... > tmpfile
mv tmpfile prefs.json


and step around it manually as well.



There is one (slight?) difference to what your code did: you made no changes for path and installationPath if "path" appeared anywhere in the file. There's no way to replicate that with jq directly, but you could split the command in two (one for path, one for all the time) if there's a necessary semantic element to that. This command will always make the change, but if it's already got the same value for a key that doesn't have any effect.




If this is a fixed set of replacements, you could also make a file with just the object from point 3 above in it literally (as true JSON, not dynamically computed), and then use



jq --slurpfile tmp rhs.json '.forgedAlliance += tmp[0]'


with the same effect as the big command above.






share|improve this answer













This jq command will make exactly those changes:



jq --arg user_path "$user_path" '
.forgedAlliance +=
installationPath: ($user_path + "/.steam/steam/steamapps/common/Supreme Commander Forged Alliance"),
path: ($user_path + "/.steam/steam/steamapps/common/Supreme Commander Forged Alliance"),
preferencesFile: ($user_path + "/.steam/steam/steamapps/compatdata/9420/pfx/drive_c/users/steamuser/Local Settings/Application Data/Gas Powered Games/Supreme Commander Forged Alliance/Game.prefs"),
executableDecorator: ($user_path + "/faf/run "%s"")
'


This uses




  1. --arg user_path "$user_path" to bring the shell variable into the jq program (you could also use the variable binding operator "'"$user_path"'" as $user_path |, but it would involve ugly quote splicing)

  2. Update-assignment .forgedAlliance += to process the whole file, updating just the value of the "forgedAlliance" key by merging it with what's on the right.

  3. A fresh object constructed from to with just the new key values you wanted computed inside it. If there are existing keys with the same name, they will be replaced.


  4. $user_path to access that variable binding we made above.

The whitespace is optional - it's just there to make it easier to read on this site.



jq always outputs as valid JSON, so you don't have any comma cleanup to do. You may find the sponge command from moreutils useful for updating the file itself, because there is no -i equivalent in jq, but you can also just redirect to another file



jq ... > tmpfile
mv tmpfile prefs.json


and step around it manually as well.



There is one (slight?) difference to what your code did: you made no changes for path and installationPath if "path" appeared anywhere in the file. There's no way to replicate that with jq directly, but you could split the command in two (one for path, one for all the time) if there's a necessary semantic element to that. This command will always make the change, but if it's already got the same value for a key that doesn't have any effect.




If this is a fixed set of replacements, you could also make a file with just the object from point 3 above in it literally (as true JSON, not dynamically computed), and then use



jq --slurpfile tmp rhs.json '.forgedAlliance += tmp[0]'


with the same effect as the big command above.







share|improve this answer












share|improve this answer



share|improve this answer










answered 2 hours ago









Michael HomerMichael Homer

50.5k8140177




50.5k8140177












  • "you made no changes for path and installationPath if "path" appeared anywhere in the file.", well looking back on that that's terrible. I prefer your approach. it does mean installing jq will have to become part of the script but maybe that's a manageable sacrifice.

    – tatsu
    45 mins ago


















  • "you made no changes for path and installationPath if "path" appeared anywhere in the file.", well looking back on that that's terrible. I prefer your approach. it does mean installing jq will have to become part of the script but maybe that's a manageable sacrifice.

    – tatsu
    45 mins ago

















"you made no changes for path and installationPath if "path" appeared anywhere in the file.", well looking back on that that's terrible. I prefer your approach. it does mean installing jq will have to become part of the script but maybe that's a manageable sacrifice.

– tatsu
45 mins ago






"you made no changes for path and installationPath if "path" appeared anywhere in the file.", well looking back on that that's terrible. I prefer your approach. it does mean installing jq will have to become part of the script but maybe that's a manageable sacrifice.

– tatsu
45 mins ago


















draft saved

draft discarded
















































Thanks for contributing an answer to Unix & Linux Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid …


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f509764%2freshaping-json-reparing-json-inside-shell-script-remove-trailing-comma%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Which organization defines CJK Unified Ideographs? The Next CEO of Stack OverflowCharacters which have several different shapesHow useful are the kanji in reading Chinese?Can Chinese readers scan large amounts of text faster/more accurately than their alphabet-using counterparts?丼: why is “well” also “bowl of food”?What Does Unicode 8.0 Mean For Chinese?How are blanks indicated for placeholders in Chinese (like ???)Is there a dictionary of standard character variants?How to display CJK Extension F?How is it decided as to which character is used on the tech terminology?How does 子 come to mean 'midnight'?

Shenzhen Football Club Índice Elenco atual | Títulos | Referências Ligações externas | Menu de navegaçãoGooglenotíciaslivrosacadêmicoeditar«"Elenco"»Site oficialexpandindo-oeee

When We Were Young (canção de Adele) Índice Antecedentes e lançamento | Faixas e formatos | Performances e covers | Desempenho nas tabelas musicais | Créditos | Histórico de lançamento | Referências Menu de navegação«Best albums of 2015»«Adele - When We Were Young (Radio Date: 22-01-2016)»«When We Were Young - Single by Adele»«Adele: Inside Her Private Life and Triumphant Return»«adele interview: world exclusive first interview in three years»«Tobias Jesso Jr: since Adele tweeted his song, he's even bigger than his dad»«Adele interviews Tobias Jesso Jr: 'I think that a couple of the ideas we had could be rap songs'»«Adele on Her Return: 'I Was So Frightened That No One Cared'»«Tobias Jesso Jr. on working with Adele: 'I was as nervous as shit'»«How Ariel Rechtshaid Pushed Adele To Her Limit»«Adele Previews 'When We Were Young' on '60 Minutes' Teaser, Tops Trending 140»«Adele Performs New '25' Ballad, "When We Were Young" Live: Watch»«Which '25' Song Should Be Adele's Next Single?»«Adele's 'When We Were Young' Confirmed As Second Single From '25'»«Adele's new single artwork for 'When We Were Young' is perfectly adorable»«Adele at the BBC review: honest, funny and spectacular – Celebrity News News»«'Saturday Night Live': Adele Sings 'Hello' and 'When We Were Young'»«'Adele: Live in New York City' NBC Special – Set List Revealed!»«Adele Closes Out the 2016 Brit Awards With 'When We Were Young'»«What Is The Adele Live Tour Set List? There's No Way She'd Leave Out These 8 Songs»«See Demi Lovato's Soaring Cover of Adele's 'When We Were Young'»«'The Voice': 5 Best Moments From Week 1 Blind Auditions»«Adele – When We Were Young (Media Control Charts)»«Adele – When We Were Young (Entertainment Monitoring Africa)»«Adele – When We Were Young (ARIA Charts)»«Adele – When We Were Young (Ö3 Austria Top 40)»«Adele – When We Were Young (Ultratop 50)»«Adele – When We Were Young (Ultratop 40)»«Adele – When We Were Young (Canadian Hot 100)»«Adele – When We Were Young (Tracklisten)»«Adele – When We Were Young (The Official Charts Company)»«Adele – Hello (IFPI Slovenská Republika)»«Adele – When We Were Young (Productores de Música de España)»«Adele – When We Were Young (Billboard Hot 100)»«Adele – When We Were Young (Pop Songs)»«Adele – When We Were Young (Adult Pop Songs)»«Adele – When We Were Young (Hot Adult Contemporary Charts)»«Adele – When We Were Young (Hot Dance Club Songs)»«Adele – When We Were Young (Rock Airplay)»«Adele – When We Were Young (IFPI Finlândia)»«Adele – When We Were Young (Syndicat National de l'Éditon Phonographique)»«Adele – When We Were Young (Magyar Hanglemezkiadók Szövetsége)»«Adele – When We Were Young (Irish Recorded Music Association)»«Adele – When We Were Young (Mexico Airplay)»«Adele – When We Were Young (VG-lista)»«Adele – When We Were Young (NZ Top 40 Singles)»«Adele – When We Were Young (MegaCharts)»«Adele – When We Were Young (Związek Producentów Audio Video)»«Adele – When We Were Young (Portugal Digital Songs)»«Adele – When We Were Young (UK Indie Singles Chart)»«Adele – When We Were Young (UK Singles Chart)»«Adele – When We Were Young (Sverigetopplistan)»«Adele – When We Were Young (Schweizer Hitparade)»«Adele – When We Were Young (Portugal Digital Songs)»«Music Canada – Gold/Platinum – When We Were Young»«NZ Top 40 Singles Chart»«Certified Awards»e