VALUE=<Нет вывода.
Здесь -документ является перенаправлением , вы не можете перенаправить в переменную.
При синтаксическом анализе командной строки перенаправления обрабатываются отдельно от назначения переменных. Поэтому ваша команда эквивалентна (обратите внимание на пробел)
VALUE= <
То есть он присваивает вашей переменной пустую строку, затем перенаправляет стандартный ввод из строки здесь -в команду (, но команды нет, поэтому ничего не происходит ).
Обратите внимание, что
<
действителен, как и
Просто нет команды, стандартный входной поток которой может содержать данные, поэтому он просто потерян.
Хотя это сработает:
VALUE=$(cat <
Здесь команда, которая получает здесь документ -, называется cat
и копирует его в свой стандартный вывод. Это то, что затем присваивается переменной посредством подстановки команд.
В вашем случае вместо этого вы могли бы использовать
python -m json.tool <
без дополнительного шага по сохранению данных в переменной.
Возможно, стоит изучить такие инструменты, как jo
, для создания данных JSON с правильной кодировкой:
Например:
jo type=account customer_id=1234 customer_email=jim@gmail.com random_data="some^Wdata"
... где ^W
— литерал Ctrl+W , выведет
{"type":"account","customer_id":1234,"customer_email":"jim@gmail.com","random_data":"some\u0017data"}
Таким образом, команду в вопросе можно было написать
jo type=account customer_id=1234 customer_email=jim@gmail.com |
python -m json.tool
Проблема в вашем коде,
awk 'BEGIN{min=9}{for(i=2;i<=2;i++){min=(min<$i)?min:$i}print min;exit}' file.dat
... заключается в том, что вы сразу exit
после обработки первой строки ввода. Ваш средний блок должен запускаться для каждой строки . Затем в блоке END
вы можете распечатать найденные значения. Вы делаете это в другом фрагменте кода:
awk '{if ($1 > max) max=$1}END{print max}'
Другая проблема заключается в том, что вы инициализируете min
магическим числом (9 в первом коде, который я цитировал, и 0 во втором фрагменте; переменные, не инициализированные явно, имеют значение 0, если вы используете их в вычислениях ). Если это магическое число не попадает в диапазон чисел в фактических данных, то рассчитанные минимальные и/или максимальные значения будут неверными. Лучше инициализировать как min, так и max некоторым значением, найденным в данных.
Чтобы отслеживать как минимальное, так и максимальное значения, вам нужны две переменные, и обе из них необходимо сверять с данными в файле для каждой строки, чтобы увидеть, нуждаются ли они в обновлении.
Поскольку awk
поддерживает массивы, было бы естественно использовать массивы для min
и max
с одним элементом массива на столбец. Это то, что я сделал в коде ниже.
Обобщается на любое количество столбцов:
NF == 0 {
# Skip any line that does not have data
next
}
!initialized {
# Initialize the max and min for each column from the
# data on the first line of input that has data.
# Then immediately skip to next line.
nf = NF
for (i = 1; i <= nf; ++i)
max[i] = min[i] = $i
initialized = 1
next
}
{
# Loop over the columns to see if the max and/or min
# values need updating.
for (i = 1; i <= nf; ++i) {
if (max[i] < $i) max[i] = $i
if (min[i] > $i) min[i] = $i
}
}
END {
# Output max and min values for each column.
for (i = 1; i <= nf; ++i)
printf("Column %d: min=%s, max=%s\n", i, min[i], max[i])
}
Учитывая этот скрипт и данные в вопросе:
$ awk -f script.awk file
Column 1: min=0.0000, max=0.4916
Column 2: min=-24.1254, max=-23.4334
Условие NF == 0
для первого блока (, которое выполняется для всех строк ), должно обеспечивать пропуск пустых строк. Тест означает "если нет полей (столбцов )данных в этой строке". Переменная initialized
будет равна нулю с самого начала (логически ложь ), но будет установлена в единицу (логически истина ), как только первая строка с данными будет читать.
Переменная nf
инициализируетсяNF
(числом полей )в строке, из которой мы инициализируем значения min
и max
.Это сделано для того, чтобы вывод в блоке END
работал, даже если в последней строке нет полей.
Использованиеdatamash
иprintf
:
for f in 1 2 ; do printf 'Column #%s\nmax - %s\nmin - %s\n\n' $f \
$(datamash -W max $f min $f < file.dat); done
...или без петли:
printf 'Column #%s\nmax - %s\nmin - %s\n\n' \
$(datamash -W max 1 min 1 max 2 min 2 < file.dat |
tr -s '\t' '\n' | paste - - | nl)
Выход одного из:
Column #1
max - 0.4916
min - 0
Column #2
max - -23.4334
min - -24.1254
На самом деле можно объединить все инструкции в одну awk
программу:
awk 'NR==1{min1=max1=$1;min2=max2=$2}\
NR>1 {if ($1<min1) {min1=$1} else if ($1>max1) {max1=$1};\
if ($2<min2) {min2=$2} else if ($2>max2) {max2=$2}; }\
END{printf("Column1 min: %f\nColumn1 max: %f\nColumn2 min: %f\nColumn2 max:%f\n",min1,max1,min2,max2)}' file.dat
Это инициализирует минимальное и максимальное значения для обоих столбцов с соответствующими значениями правила первой строки (с условием NR==1
), а затем сканирует последующие строки, чтобы увидеть, не превышают ли значения текущий максимум/ меньше текущего минимума, соответственно правилу (с условиемNR>1
).
В конце файла (правило с условиемEND
)выводит результат.
Обратите внимание , что это предполагает отсутствие пустых строк . Если они есть, вы должны заменить условие NR>1
на NR>1 && NF>0
. Если перед первой строкой могут быть пустые строки ,использовать
awk '!init && NF>0 {init=1; min1=max1=$1; min2=max2=$2} \
init==1 && NF>0 {if ($1<min1) {min1=$1} else if ($1>max1) {max1=$1};\
if ($2<min2) {min2=$2} else if ($2>max2) {max2=$2}; }\
END{printf("Column1 min: %f\nColumn1 max: %f\nColumn2 min: %f\nColumn2 max:%f\n",min1,max1,min2,max2)}' file.dat
При этом будет использоваться переменная init
, чтобы проверить, была ли уже найдена не -пустая строка, и использовать содержимое первой не -пустой строки, чтобы предварительно -установить текущий максимум/минимум для обе колонки. Только если init
установлен (после этой инициализации ), (не -пустые )строки учитываются для ввода этой статистики.
Общее замечание: никогда не нужно cat
файл и передавать результат в awk
.
Попробуйте это,
awk '{if (max == "") max=$2 ; else if ($2 > max) max=$2}END{print max}' file
awk '{if (min == "") min=$2 ; else if ($2 < min) min=$2}END{print min}' file
Проблемы с кодом:
exit
пока не будут обработаны все входные данные. На самом деле выход не нужен. min > $1
, будет ложной, поскольку min еще не имеет значения (, поэтому по умолчанию используется числовое значение 0
). Общее решение для любого количества полей (в пределах разумного )в любой строке (количество полей не обязательно должно быть постоянным )которое предполагает только, что пустое поле содержит нуль(""
)и который принимает все значения, которые принимает awk (обычно строки преобразуются в0
)это:
awk '
{
if(nf<NF){nf=NF}; # find the max number of fields
# to print at the end
for(i=1;i<=NF;i++){
f=$i+0; # convert each field to a number
# Either initialize (if empty)
# or capture max and min.
if(max[i]==""||max[i]<f){ max[i]=f }
if(min[i]==""||min[i]>f){ min[i]=f }
}
}
END{
for(i=1;i<=nf;i++){print i,min[i],max[i]}
}' file
В этом коротком файле (пример):
0.1735 -23.6900
0.2024 -23.7324
0.2313 -23.7745
0.2602 -23.8162 23 -12 PREC
0.2892 -23.8574 46 -23
0.3181 -23.8980
Вывод будет:
1 0.1735 0.3181
2 -23.898 -23.69
3 23 46
4 -23 -12
5 0 0
Для вашего файла будет напечатано:
1 0 0.4916
2 -24.1254 -23.4334
Это для столбца 1 (Он вычисляет среднее максимальное и минимальное значение)
sort -n -k 1 file |awk '{SUM+=$1 ; if ( NR == 1) MIN=$1} END{print "Average - "SUM/NR, "Min time - "MIN,"Max Time - "$1}'
это для столбца 2
sort -n -k 2 file |awk '{SUM+=$1 ; if ( NR == 1) MIN=$1} END{print "Average - "SUM/NR, "Min time - "MIN,"Max Time - "$1}'