나는 이것을 위해 많은 검색을 해왔지만 이 필요성에 대한 전조는 없는 것 같습니다.
셸 스크립트의 일부로 프로그래밍 방식으로 응용 프로그램 기본 설정 파일을 편집해야 합니다.
그리고 기본 설정은 엄격한 json 형식으로 저장됩니다. 즉, ,
닫는 중괄호 앞에 쉼표가 있으면 해당 기본 설정 파일을 로드하는 애플리케이션이 시작 시 충돌을 일으킵니다 }
.
일반적으로 이것은 문제가 되지 않습니다.
나는 sed
그에 따라 s를 사용합니다. 오류 텍스트가 포함된 줄이 예제 파일의 섹션 끝에 있는 경우 이 텍스트를 바꿀 때언제나쉼표가 없습니다.
교체하려는 다른 결함이 있는 비트가 포함된 다른 라인이 끝에 있지 않은 경우,언제나쉼표를 포함하여 바꾸십시오.
예:
_
( 교체할 문자열이 때때로 백슬래시로 가득 차 있기 때문에 sed에서 구분 기호로 밑줄을 사용합니다 )
sed -i 's_"executableDecorator".*_"executableDecorator": "'$user_path'/faf/run \\"%s\\"",_' $user_path/.faforever/client.prefs
줄이 끝에 있는 경우:
sed -i 's_"executableDecorator".*_"executableDecorator": "'$user_path'/faf/run \\"%s\\""_' $user_path/.faforever/client.prefs
이것회의그래도 작동합니다! ...
둘 다 동시에 기본 설정을 편집하지 않도록 스크립트를 실행하기 전에 애플리케이션을 종료했지만, 그럼에도 불구하고 내 스크립트가 받는 기본 설정은 애플리케이션의 비동기 실행으로 인해 매번 달라집니다.
이것은 완전히 무작위입니다.
때로는 한 줄이 중간에 있을 수도 있고 때로는 끝에 있을 수도 있습니다. 애플리케이션 자체(Java 및 일부 json java lib)는 컨텍스트에 따라 쉼표를 추가하는 방법을 알고 있지만 쉘 스크립트의 일부로... 일이 부풀어오르는 것 같은 느낌이 듭니다.
(그렇지 않다면 다음 줄이 인지 아닌지에 따라 쉼표가 있는지 확인하는 속기가 있습니다 }
. 그러면 이것이 제가 더 관심을 가질 만한 더 간단한 솔루션입니다.)
그러나 현재로서는 쉘 스크립트의 모든 작업을 마친 후 json prefs 파일을 "정리"할 수 있도록 json을 수정하는 POSIX 유틸리티를 찾고 있습니다... 그런 것이 존재합니까?
편집하다:
기본 파일(전체 파일)은 다음과 같습니다.
{
"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
}
유일하게 중요한 부분은 다음과 같습니다 "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\""
},
나는 이것을 얻기 위해 다음 명령을 실행합니다.
"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\""
},
유효한 명령(표준 경우 개체가 이동하지 않음)은 다음과 같습니다.
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
답변1
이것jq 명령다음과 같은 변경 사항이 적용됩니다.
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\"")
}'
이는 다음을 사용합니다.
--arg user_path "$user_path"
쉘 변수를 jq 프로그램으로 가져오기(당신은 또한 사용할 수 있습니다변수 바인딩 연산자"'"$user_path"'" as $user_path |
, 그러나 여기에는 추악한 인용 결합이 포함됩니다)- 전체 파일을 처리하도록 할당을 업데이트하고
.forgedAlliance +=
"forgedAlliance" 키 값만 업데이트합니다.병합하다오른쪽에 내용이 있습니다. - 신선한 것생성된 객체는 다음에서
{
다음 으로 이동합니다.}
그 안에는 계산하려는 새 키 값만 포함하세요. 동일한 이름을 가진 기존 키가 있으면 교체됩니다. $user_path
위에서 만든 변수 바인딩에 액세스합니다.
공백은 선택 사항입니다. 단지 사이트를 더 쉽게 읽을 수 있도록 하기 위한 것입니다.
jq는 항상 유효한 JSON을 출력하므로 쉼표 삭제를 수행할 필요가 없습니다. 당신은 찾을 수 있습니다sponge
moreutils의 명령jq에는 해당 파일이 없으므로 파일 자체를 업데이트하는 데 유용 -i
하지만 다른 파일로 리디렉션할 수도 있습니다.
jq ... > tmpfile
mv tmpfile prefs.json
수동으로 우회하세요.
코드에서 수행하는 작업과 한 가지(약간?) 다른 점은 파일의 아무 곳에나 "경로"가 나타나면 path
아무 것도 변경하지 않은 것입니다. installationPath
jq를 사용하여 명령을 직접 복제할 수 있는 방법은 없지만 필요한 의미 체계 요소가 있는 경우 명령을 두 부분(경로용 부분과 항상 부분용)으로 나눌 수 있습니다. 이 명령은언제나변경합니다. 하지만 이미 동일한 키 값이 있으면 아무런 효과가 없습니다.
이것이 고정된 대체 세트인 경우 위의 3번 항목의 객체만 포함하는 파일을 생성한 다음(동적으로 계산되지 않은 실제 JSON) 다음을 사용할 수도 있습니다.
jq --slurpfile tmp rhs.json '.forgedAlliance += tmp[0]'
효과는 위의 big 명령과 동일합니다.
답변2
문자열 교체의 경우 아래 자리 표시자 A, B에 문자열을 배치하고
A의 모든 /를 \/로 이스케이프하고 ~를 _ 대신 sed 하위 구분 기호로 사용합니다. 예:
A -> "executableDecorator":
(B 새로 삽입된 문자열)
sed -E '/A/{N;/A.*\n\s*\}/ {s~(A).*\n~\1B\n~;b} ;s~(A).*\n~\1B,\n~ }' B.json
일부 확장 예시;
sed -E '/"executableDecorator":/{N;/"executableDecorator":.*\n\s*\}/ {s~("executableDecorator":).*\n~\1B\n~;b} ;s~("executableDecorator":).*\n~\1B,\n~ }' B.json