Несколько команд sed в Bash

Несколько команд sed в Bash

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

Я использовал 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

решение1

Чтобы поместить несколько 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удаляет кавычки из выходных строк (сыройрежим)

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

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

решение2

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

К сожалению, в coreutils нет хороших инструментов для работы с JSON.Этти предоставил 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()))'

решение3

Для простого удаления символов, которое вы делаете в этих 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команд, каждая из которых работает независимо, их объединение может быть наиболее простым способом, используя sedопцию "-f" для чтения отдельных команд из файла. Вы просто помещаете строки 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преобразуются все символы % в пары символов "; ".)

решение4

Вы можете объединить это следующим образом:

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

Связанный контент