Можно ли сопоставить несколько условий в одном операторе case?

Ваша awkпрограмма верна, если мы изменим ее на безусловно используем

print $0","( a[$3] ? a[$3] : 0 )

вместо использования

print $0","a[$3]

, когда a[$3]не равен -нулю или пуст. То есть используйте ноль, если поле a[$3]равно нулю или пусто, в противном случае используйте a[$3].

Другими словами,

awk -F, -v OFS=',' 'FNR==NR { a[$1]=$2; next } FNR > 1 { print $0, (a[$3] ? a[$3] : 0) }' fileB fileA

Здесь мы используем FNR > 1, чтобы пропустить заголовок.


Использованиеjoin:

$ join -t, -1 3 -o 1.1,1.2,1.3,1.4,2.2 fileA fileB
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz
4,1993,6050,912432,1.8 GHz
5,1994,6003,912433,850 MHz

Если файлы не отсортированы по ключу соединения, то (в оболочке, поддерживающей подстановки процессов):

$ join -t, -1 3 -o 1.1,1.2,1.3,1.4,2.2 <( sort -t, -k3,3 fileA ) <( sort fileB )
5,1994,6003,912433,850 MHz
4,1993,6050,912432,1.8 GHz
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz

joinвыполнит операцию INNER JOINнад двумя файлами. -t,сообщает join, что запятые являются разделителем полей, и мы выбираем третье поле в качестве ключа соединения в первом файле с-1 3(первое поле во втором файле считается ключом, если мы не используем -2 Nдля того же другого поля Nв этом файле ).

Флаг -oсообщает join, какие поля мы хотели бы включить в вывод и из какого файла(x.yозначает столбец yиз файлаx).

join— очень быстрая операция, но она требует сортировки входных файлов по ключу соединения (нам просто повезло с первым примером выше ). Окончательный вывод во втором примере выше не отсортирован по отношению к первому полю , но вы можете легко исправить это, передав его через sort -k1,1n.


Для второго сценария с несоответствием

$ join -t, -1 3 -o1.1,1.2,1.3,1.4,2.2 -a 1 -e 0  <( sort -t, -k3,3 fileA ) <( sort fileB )
5,1994,6003,912433,850 MHz
6,1995,6004,21234,0
4,1993,6050,912432,1.8 GHz
A,B,C,D,0
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz

Добавляя -a 1 -e 0, мы просим joinвсегда выводить все поля из первого файла(-a 1)и вставлять нули для каждого поля, отсутствующего во втором файле.

Как видите, теперь мы получаем правильный результат, но заголовок из первого файла также включен (, потому что мы просили об этом ). Если вы хотите удалить заголовки из данных обоих файлов (и отсортировать результат ), то

$ join -t, -1 3 -o1.1,1.2,1.3,1.4,2.2 -e 0 -a1  <( tail -n +2 fileA | sort -t, -k3,3 ) <( tail -n +2 fileB | sort ) | sort -k1,1n
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz
4,1993,6050,912432,1.8 GHz
5,1994,6003,912433,850 MHz
6,1995,6004,21234,0

Эта команда будет работать в обоих сценариях.

22
03.04.2020, 07:52
2 ответа

Нет, базовая структура оператора case такова, что выполняется только один соответствующий сегмент. За исключением падения -, через которое вы отвергаете. Кроме того, он работает только с некоторыми оболочками, а не со всеми, и имеет синтаксис, специфичный для каждой оболочки. Синтаксис Bash для перехода с -на конец — ;;&. В ksh или zsh единственный доступный ;&не выполняет следующий тест, только непосредственное выполнение сегмента (будет печатать обе строки для всех случаев вTue|Wed|Thu|Fri).

Единственный вариант для кейса — разбить его на две строки:

esac
case $now in

Как это (Пожалуйста!, оставьте переменные в ПРОПИСНЫХ РЕГИСТРАХ для переменных окружения):

#!/bin/bash
now=$(date +"%a")
case $now in
    Mon)
        echo "Mon";;
    Tue|Wed|Thu|Fri)
        echo "Tue|Wed|Thu|Fri";;
esac
case $now in
    Fri|Sat|Sun)
        echo "Fri|Sat|Sun";;
    *) ;;
esac
1
28.04.2021, 23:18

Другой вариант :использования функций.

$ cat tt
#!/bin/bash

mon()     { echo "  Mon"             ; }
tue_fri() { echo "  Tue|Wed|Thu|Fri" ; }
fri_sun() { echo "  Fri|Sat|Sun"     ; }

now=$(date +"%a")
[[ $1 != "" ]] && now=$1      # use for testing

case $now in
  Mon)         mon              ;;
  Tue|Wed|Thu) tue_fri          ;;
  Fri)         tue_fri; fri_sun ;;
  Sat|Sun)     fri_sun          ;;
  *)           echo "  ERROR"   ;;
esac

и проверьте с помощью

$ for f in Mon Tue Wed Thu Fri Sat Sun bla ;do echo "$f"; tt "$f"; done
Mon
  Mon
Tue
  Tue|Wed|Thu|Fri
Wed
  Tue|Wed|Thu|Fri
Thu
  Tue|Wed|Thu|Fri
Fri
  Tue|Wed|Thu|Fri
  Fri|Sat|Sun
Sat
  Fri|Sat|Sun
Sun
  Fri|Sat|Sun
bla
  ERROR
1
28.04.2021, 23:18

Теги

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