Есть ли более чистый способ добавить else if к условному назначению в Awk и т. д.?

Некоторые языки, такие как скрипт awk, допускают условные присваивания. Например, предположим, что у вас есть файл списка в формате:

<item name, no spaces> <price as float>

e.g.

Grape 4.99
JuicyFruitGum 0.45
Candles 5.99

И вы хотели обложить налогом все, что превышает 1 доллар... вы могли бы использовать awk-скрипт:

awk '{a=($2>1.00)?$2*1.06:$2; print a}' prices.data

... который использует условное присваивание для сокращения синтаксиса.

Но скажем, вы хотели также предложить 1 доллар на все товары дороже 20 долларов и 2 доллара на товары дороже 40 долларов. Что ж, на таком языке, как c, вы обычно делаете что-то вроде:

if (price > 40.00) {
   price-=2; 
   price *= 1.06; 
}
else if ( price > 20.00 && price <= 40.00 ) {
   price--; 
   price *= 1.06; 
}
else if ( price > 1.00 ) {
   price*=1.06;
}

... ну, я обнаружил, что вы можете класть awk или другие языки сценариев в составное назначение. например.:

awk '{a=($2>1.00)?($2>20.00)?($2-1)*1.06:($2>40.00)?($2-2)*1.06:$2*1.06:$2; print a}' prices.data

Мои вопросы заключаются в том, что

a) составное присваивание (подобное этому) вообще универсально совместимо с языками сценариев, поддерживающими условное присваивание?
b) есть ли способ сделать многоусловное назначение в скрипте awk, не связанный с кладжом?

Для уточнения: я говорю исключительно о сокращении присваивания (‹...>?‹...>:‹...>;, а не о традиционном условном присваивании, которое я уже умею выполнять составное присваивание в стиле C для в сценарии Awk. В качестве примечания, почему я могу использовать стенографию, я думаю, что ее достоинство очевидно — она короткая. Но, как и в случае с регулярными выражениями, вы можете написать хорошее описание того, что ваш запутанный синтаксис делает для потомков.


person Jason R. Mick    schedule 14.09.2010    source источник


Ответы (3)


а)

Bash, ksh и zsh поддерживают составные условные (троичные) операторы (однако Bash не работает с числами с плавающей запятой):

for i in {3..5}; do for j in {2..6}; do for k in {2..4}; do
    (( a = i > j ? i > k ? j > k ? i * j : i * k : j * k : 0 ))
    echo $a
done; done; done

Синтаксис тернарных операторов PHP аналогичен.

Python совсем другой:

a = b if c else d if e else f if g else h

Bash и др., а также Ruby (который также поддерживает форму ?:) поддерживают этот стиль (показана версия Bash):

[[ condition ]] && do_if_true || do_if_false

что можно сделать в сложной форме. Это может выполнять действия в дополнение к назначениям.

b) нет, не без явного if/else (или прибегая к еще большему нелепому творчеству.

person Dennis Williamson    schedule 15.09.2010
comment
Вау, отличный ответ! Вы, сэр, настоящий эксперт по сценариям. Как раз та информация, которую я собирался просмотреть... Вы когда-нибудь думали о написании книги по сценариям? :П - person Jason R. Mick; 15.09.2010
comment
@Jason: Эта мысль пришла мне в голову, но в книгах больше нет денег. - person Dennis Williamson; 16.09.2010
comment
Может тогда сайт? :P Похоже, что есть способ использовать этот образовательный талант с пользой в денежном выражении. Однако частая (бесплатная) помощь приветствуется! - person Jason R. Mick; 17.09.2010

На самом деле, в C тоже есть оператор ?, так что вы можете сделать то же самое (некрасиво) с C.

Тем не менее, вы, по сути, делаете там код только для записи. Если бы вы не сказали мне, что делает это выражение awk, мне было бы очень трудно в этом разобраться. Почему бы просто не использовать if?

Вы поблагодарите себя через 6 месяцев, когда обнаружите необходимость настроить его.

person T.E.D.    schedule 14.09.2010
comment
Если вы понимаете синтаксис, вы можете разбить его на серию операторов if, и это не должно быть слишком сложно понять. Кроме того, для этого и нужны комментарии в вашем файле однострочников :) Мне это нравится, потому что оно КОРОТКОЕ, но я бы предпочел правильное составное условное сокращение, если есть такая вещь... - person Jason R. Mick; 15.09.2010

а) я так думаю

(б) Да


Как оказалось, ваш код на "C" почти легален для awk. Следующая слегка измененная версия отлично работает как программа awk...

/./ {
  price = $1
  if (price > 40.00) {
     price -= 2 
     price *= 1.06 
  } else if ( price > 20.00 && price <= 40.00 ) {
     price-- 
     price *= 1.06 
  } else if ( price > 1.00 ) {
     price *= 1.06
  }
  printf("%6.2f\n", price)
}

Я убрал точки с запятой, но ничего страшного не произойдет, если их оставить...

person DigitalRoss    schedule 14.09.2010
comment
эээ... Я имел в виду исключительно стенографию присваивания (‹...›)?‹...››:‹...› ... Я уже знаю, как составить составное присваивание, используя традиционные условные операторы. Я добавил дополнительные пояснения к своему сообщению, чтобы никто больше не был сбит с толку, как вы. - person Jason R. Mick; 15.09.2010
comment
Хорошо, понял, но ты сказал на таком языке, как Си, и было круто, что твой Си работал в awk. Очевидно, что существует общая эквивалентность ?: и if-then-else. Теперь крутая граница находится в чем-то вроде Ruby, который позволяет вам сказать (x?y:z; whatever; if x ...; and_do_something_else), и вы можете поместить это где угодно, включая произвольные операторы в выражениях в ((((()))))... - person DigitalRoss; 15.09.2010
comment
Да, я вижу, что это было немного запутанно... извините за это. Звучит как интересный инструмент для составного исполнения в Ruby... - person Jason R. Mick; 15.09.2010