3

У меня есть имя файла и пароли в формате JSON, которые я хочу преобразовать в процесс.

Я использовал sed в разных командах для его обработки, но я хотел бы знать, как объединить все три команды в одну на будущее.

Оригинальный формат

    { "user.name1" : "hashed_password",
"user.name2" : "hashed_password" }

Желаемый вывод

user.name:hashed_password

Это команды, которые я выполнил, однако мне не удалось связать их вместе, используя либо конвейерную связь, либо просто конкатенируя их, где я получаю сообщение об ошибке sed: -e expression #1, char 8: unknown option to 's' .

Оскорбительная команда ...

sed -i 's/\"//g/s/\,/\n/g/\s//g' input_file 
sed: -e expression #1, char 8: unknown option to `s'

Как можно объединить приведенные ниже команды в одну?

Команды Удалить двойные кавычки

sed -i 's/\"//g' input_file

Заменить запятую на новую строку

sed -i 's/\,/\n/g' input_file

Удалить пробелы

sed -i 's/\s//g input_file

5 ответов5

16

Чтобы поместить несколько команд sed в один « скрипт », вы можете использовать несколько флагов -e (которые переносимы):

sed -i -e 's/\"//g' -e 's/\,/\n/g' -e 's/\s//g' input_file

Или разделитель точки с запятой (который доступен не во всех реализациях):

sed -i 's/\"//g;s/\,/\n/g;s/\s//g' input_file

Вам также нужно добавить обработку для фигурных скобок - {} ...


Сказав это, чтобы правильно проанализировать и обработать JSON, вам не следует использовать sed ... возможно, попробуйте jq !

jq -r 'keys[] as $k | "\($k):\(.[$k])"' input_file

Выход:

user.name1:hashed_password
user.name2:hashed_password
  • keys[] as $k будет перебирать каждый ключ, сохраняя его значение в $k
    • то есть: user.name1 , user.name2
  • "\($k):\(.[$k])" сформирует строку, подставив в $k и .[$k]
  • Использование -r удаляет кавычки из выходных строк (режим raw )

Использование sed для обработки JSON откроет вам все виды проблем ... например, как бы вы справились со следующим (полностью корректным JSON) вводом?

{
    "user.name1" :
        "hashed_password",
    "user.name2" :
        "hashed_password"
}
3

Когда вы имеете дело со стандартным вводом, таким как JSON, обычно лучше использовать правильный анализатор, а не регулярное выражение. Например, вы будете правильно преобразовывать любые escape-последовательности (хотя это может быть невозможно с вашими конкретными входными данными!).

К сожалению, в coreutils нет хороших инструментов для работы с JSON. Attie предоставляет jq как достойный вариант, если вы можете свободно устанавливать пакеты.

Если вы не можете установить дополнительные пакеты, это не особенно сложно в Python. Возьмите этот скрипт, например:

import json,sys
for (k, v) in json.load(sys.stdin):
    print(k + ":" + v)

Который можно сжать в одну строку:

cat inputdata | python -c 'import json,sys;print("\n".join((k + ":" + v) for (k, v) in json.load(sys.stdin).items()))'
0

Sed может справиться с многострочным редактированием, но я согласен с Атти и Бобом, анализ json с sed regex может стать кошмаром.

sed -nr '/\{/ b Load ; d
: Load
/\}/ b Edit ; N ; b Load
: Edit ; s/[^"]+"([^"]+)"[^"]+"([^"]+)"(.*)/\1:\2\n\3/ ; t Print ; d
: Print ; P ; s/[^\n]+\n// ; t Edit' <<'eof'
{
    "user.name1" :
        "hashed_password1",
    "user.name2" :
        "hashed_password2"
}
    { "user.name3" : "hashed_password3",
"user.name4" : "hashed_password4" }

{ "user.name5":"hashed_password5"}
eof

user.name1:hashed_password1
user.name2:hashed_password2
user.name3:hashed_password3
user.name4:hashed_password4
user.name5:hashed_password5
0

Для простого удаления символов, которое вы выполняете в этих командах sed я бы вместо этого рекомендовал вам использовать tr , единственная цель которого - удалять, сжимать или заменять отдельные символы, включая символы новой строки (sed основан на регулярных выражениях, которые обычно полагаются на символы новой строки как разделители буфера, поэтому использование sed для изменения новых строк довольно сложно). Я думаю, что эта команда tr делает все, что вы ищете:

cat json_filename | tr -d "{}\" \012\011\015" | tr "," "\012"

Первая команда tr удаляет все фигурные скобки, двойные кавычки, пробелы, возврат каретки (восьмеричный 012, ascii 10), символы табуляции (восьмеричный 011, ascii 9 и символ перевода строки (восьмеричный 015, ascii 13). Вторая команда tr заменяет все запятые на возврат каретки. Пока имена и значения переменных вашего JSON-файла не содержат запятых, эти команды позволят вам избежать необходимости выделенного анализатора JSON.

Тем не менее, если у вас есть набор команд sed , каждая из которых работает независимо, объединить их проще всего с помощью опции «-f» sed для чтения отдельных команд из файла. Вы просто положите S /.../.../g строки в файл, каждая строка в отдельной строке, затем укажите это имя файла после опции "-f". Например, если три перечисленные вами команды sed являются удовлетворительными, вы можете поместить их в файл с именем "json.convert.sed", который просто содержит это:

s/\"//g 
s/\,/\n/g
s/\s//g

Затем вы бы вызвали sed с этим командным файлом, используя:

sed -f json.convert.sed

Тем не менее, эти команды sed не работают для меня, чтобы выполнить то, что вы хотите, и я не уверен, что вы когда-либо сможете использовать sed для изменения символов новой строки. Это связано с тем, что sed основан на старом редакторе строк "ed", предназначенном для редактирования отдельных строк за раз (версия, доступная для сценариев), поэтому каждая строка ввода "анализируется" с использованием новых строк в качестве разделителей, затем строка (без новой строки) передается в механизм редактирования, применяются команды редактирования, затем отредактированная строка выводится с новой строкой. Затем цикл повторяется. Я только когда-либо мог использовать sed для изменения новой строки, сначала изменив символы новой строки на какой-то отдельный символ (который иначе не появляется на входе), используя tr . Нет смысла использовать tr таким образом, если все, что вы хотите сделать, это удалить переводы строки, так как tr сделает это за вас. Но если, например, вы хотите преобразовать переводы строки в точки с запятой с завершающим пробелом, один из способов сделать это будет:

cat input_file | tr "\012" "%" | sed "s/%/; /g"

(переводы строк преобразуются в% на tr , затем sed преобразует все символы% в пары символов ";".)

-1

Вы можете объединить это так:

sed -i 's/\"//g;s/\,/\n/g;s/\s//g' input_file

Вы забыли добавить удаление {} . Так что вы, вероятно, хотите:

sed -i 's/\"//g;s/\,/\n/g;s/\s//g;s/{//g;s/}//g' input_file

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .