Шаблон sed заменить «на \» и \ на \\ кроме строки json

for file in $(find /home/user/dump/ -name "*.swf")
do
  year=$(echo ${file}|cut -d_ -f1)
  month=$(echo ${file}|cut -d_ -f2)
  day=$(echo ${file}|cut -d_ -f3)
  if [ ! -d /home/user/save/${year}/${month}/${day} ]
  then
    mkdir -p /home/user/save/${year}/${month}/${day}
  fi
  mv ${file} /home/user/save/${year}/${month}/${day}
done
2
09.04.2019, 12:44
3 ответа

Чтобы быть более надежным, вы можете выполнить полный разбор json:

perl -0777 -pe '
  s@(".*?"|\\)|(\{(?:"(?:\\.|[^"])*+"|(?2)|[^"{}]++)*+\})|[^{}\\"]+@
  $1 ? $1 =~ s/["\\]/\\$&/gr : $&@gse'

Который на входе вида

"a"     "b"     "c{d"
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
{
  "1": {"x": "y"}
  "2": "}}}"
  "3": ["{\"x", "}"]
}
\uff08\u524d\u5bfe\u5fdc

дает

\"a\"     \"b\"     \"c{d\"
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
{
  "1": {"x": "y"}
  "2": "}}}"
  "3": ["{\"x", "}"]
}
\\uff08\\u524d\\u5bfe\\u5fdc

Вы можете уточнить, что вы хотите сделать, если входные данные содержат "foo\"bar"или "foo\nbar"вне объектов json.

5
27.01.2020, 21:51
$ sed 's/\(\\\|^"\|"$\|"[ \t]\)/\\\1/g' test.txt | sed 's/\([ \t]\)"/\1\\"/g'
  • Заменить \или "в начале или конце строки или перед символом пробела/табуляции:
    's/\(\\\|^"\|"$\|"[ \t]\)/\\\1/g'
  • или "после символа пробела/табуляции:sed 's/\([ \t]\)"/\1\\"/g'

Таким образом, это работает, только если ваша строка json не содержит пробелов/символов табуляции и находится на одной строке.

0
27.01.2020, 21:51

В показанном вами простом примере это легко сделать. Просто экранируйте символы только в строках, которые не начинаются с{:

$ sed -E '/^[^{]/s|(["\])|\\\1|g' file 
\"a\"     \"b\"     
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
\\uff08\\u524d\\u5bfe\\u5fdc

Однако все становится значительно сложнее, если ваш JSON может занимать несколько строк. Для таких случаев вы можете написать небольшой скрипт, который подсчитывает количество открытий {и закрытий }и применяет замену только тогда, когда эти числа равны (, поэтому, когда мы не в строке JSON ). Что-то вроде:

perl -F'' -ne 'for (@F){$op++ if /{/; $cl++ if /}/; if($cl==$op){s|["\\]|\\$&|g;}print}' file 

Однако это также не работает, если сама строка JSON может содержать {или }, которые не обозначают раздел JSON (, например. {"1":"b-{c}"}или как там ). В таких случаях вместо этого используйте подход Стефана .

3
27.01.2020, 21:51

Теги

Похожие вопросы