AWK в одну строку передать несколько команд - PullRequest
0 голосов
/ 10 сентября 2018

Я хотел бы объединить следующие несколько команд awk в одну программу awk:

awk -F 'FS' '{ $1 = ($1 == "}" ? "" : $1) } 1' sorce > destfil
awk -F 'FS' '{ $3 = ($3 == "]" ? "" : $3) } 1' sorce > destfil
awk -F 'FS' '{ $5 = ($5 == "}" ? "}," : $5) } 1' sorce > destfil

Я пытался выполнить это, используя &&, но результат не тот, который я ожидал.

awk -F 'FS' '{ $1 = ($1 == "}" ? "" : $1) &&  $3 = ($3 == "]" ? "" : $3) && $5 = ($5 == "}" ? "}," : $5) } 1' sorce > destfil

Кажется, что в выводе есть несколько нулей.

Вопрос:

  • Как мне объединить эти строки?
  • Каково происхождение нулей?

Спасибо!


@ RavinderSingh13, так как я попробовал ваш код, пример входного файла и выходного файла, как показано ниже

[user@restt]$ tail source
    {
    }
  ]
}
{
  " e t
    {
    }
  ]
}
[user@test]$ awk -F 'FS' '{$1=($1=="}"?"":$1); $3=($3=="]" ? "" : $3) ; $5=($5=="}" ? "}," :$5);} 1' source > target
[user@test]$ tail target
    {
    }
  ]
}
{
  " e t
    {
    }
  ]
}

Я думаю, что проблема связана с разделителем полей -F 'FS', или я не был уверен.


@ kvantour, ниже я дал свой пример входного файла и команду, что я запускаю и какой вывод я получаю и что мне нужно.

Содержание исходного файла:

{
  "metadata": [
    {
      sample content line 1
      sample content line n


    }
  ]
}
{
  "metadata": [
    {
      sample content line 1
      sample content line n


    }
  ]
}
{
  "metadata": [
    {
      sample content line 1
      sample content line n


    }
  ]
}
{
  "metadata": [
    {
      sample content line 1
      sample content line n


    }
  ]
}

Команда, которую я выполняю

$ awk '($1=="}"){$1="First Column"}
       ($3=="]"){$3="third Column"}
       ($5=="}"){$5="Fifth Column"}
       {$1=$1}1' sample.json > out

Вывод получаю:

[root@centos-src ~]# cat out

{
"metadata": [
{
sample content line 1
sample content line n


First Column
]
First Column
{
"metadata": [
{
sample content line 1
sample content line n


First Column
]
First Column
{
"metadata": [
{
sample content line 1
sample content line n


First Column
]
First Column
{
"metadata": [
{
sample content line 1
sample content line n


First Column
]
First Column

но я ожидаю, что результат будет:

{
  "metadata": [
    {
      sample content line 1
      sample content line n


    Fifth Column
  third Column
First Column
{
  "metadata": [
    {
      sample content line 1
      sample content line n


    Fifth Column
  third Column
First Column
{
  "metadata": [
    {
      sample content line 1
      sample content line n


    Fifth Column
  third Column
First Column
{
  "metadata": [
    {
      sample content line 1
      sample content line n


    Fifth Column
  third Column
First Column

Ответы [ 4 ]

0 голосов
/ 11 сентября 2018

Это то, что вы пытаетесь сделать (учитывая ваш source входной файл)?

$ awk '
    BEGIN{ FS="[ ]"; map[1,"}"]=map[3,"]"]=map[5,"}"]="" }
    { for (i=1;i<=NF;i++) $i=((i,$i) in map ? map[i,$i] : $i); print }
' file
    {



{
  " e t
    {
0 голосов
/ 10 сентября 2018

Использование ; для разделения операторов:

awk ... '{ $1 = ($1 == "}" ? "" : $1); $3 = ($3 == "]" ? "" : $3); $5 = ($5 == "}" ? "}," : $5); } 1' ...
0 голосов
/ 10 сентября 2018

В хорошей структуре awk можно написать:

awk -F 'FS' '($1=="}"){$1=""}
             ($3=="]"){$3=""}
             ($5=="}"){$5="},"}
             {$1=$1}1' <file>

Причина, по которой я добавляю $1=$1 в список, состоит в том, чтобы повторно обработать $0 для получения правильного OFS в случае, если ни одно из вышеуказанных условий не было выполнено. Если вы этого не сделаете, у вас будут строки, напечатанные FS в качестве разделителя полей, а другие - OFS.

Так почему вы получаете кучу нулей?

Давайте посмотрим на ваш однострочник:

$1 = ($1 == "}" ? "" : $1) &&  $3 = ($3 == "]" ? "" : $3) && $5 = ($5 == "}" ? "}," : $5)

И упростим его, предположив, что троичные операторы в скобках возвращают переменную. Таким образом, мы можем переписать его как:

$1 = var1 && $3 = var3 && $5 = var5

Учитывая, что:

  • expr1 && expr2 имеет более высокий приоритет, чем value = expr.
  • lvalue = expr возвращает значение expr

Мы видим, что awk интерпретирует это как

$1 = var1 && ($3 = (var3 && ($5 = var5) ) )

Итак, результат будет:

$5 = var5
$3 = var3 && $5  equalling var3 && var5
$1 = var1 && $3  equalling var1 && var5

Это видно в следующем примере:

$ echo "a b c d e f" | awk '{ $1="p" && $3 = "q" && $5 = "r"}1'
1 b 1 d rf

Наконец, в awk пустая строка и числовой ноль имеют логическое значение false и все остальное true . Так как два ваших исходных троичных оператора могут возвращать пустые строки, они гарантируют, что логическое И вернет false, что эквивалентно числу ZERO. Следовательно, $1 и $3 будут совпадать с нулем, если исходное значение $3 равно ]

Обновление (после получения [mcve])

То, что вы пытаетесь достичь, не так просто. Во-первых, кажется, вы предполагаете, что номер столбца подразумевает номер символа в строке. К сожалению, это не так. Awk в режиме по умолчанию предполагает, что поле $n является n -ым словом в строке, где слово - это последовательность символов, не содержащая пробелов. Итак, в следующем тексте

    }
  ]
}

все символы фактически обозначены $1.

При условии, что ваш JSON-файл имеет идеальный отступ, можно использовать следующее:

awk '/^} *$/{$0="First Column"}
     /^  ] *$/{$0="  Thrid Column"}
     /^    } *$/{$0="    Fifth Column"}
     {print $0}' <file>

Однако, если ваш файл JSON не имеет одинакового отступа, все становится довольно грязным. Проще всего сначала проанализировать файл с jq как

jq . <json-file> | awk ...
0 голосов
/ 10 сентября 2018

Поскольку вы не показали свой образец Input_file и не смогли его протестировать, попробуйте выполнить следующее.

awk -F 'FS' '{$1=($1=="}"?"":$1);$3=($3=="]"?"":$3);$5=($5=="}"?"":$5);} 1' sorce > destfil
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...