У меня есть два столбца в файле, и я хочу автоматизировать суммирование обоих значений в строке
Например
read write
5 6
read write
10 2
read write
23 44
Затем я хочу просуммировать «прочитанное» и «записанное» каждой строки. В конце концов, после суммирования я нахожу максимальную сумму и помещаю это максимальное значение в файл. Я чувствую, что мне нужно использовать grep -v, чтобы избавиться от заголовков столбцов в каждой строке, что, как указано в ответах, делает код неэффективным, поскольку я использую весь файл только для чтения строки.
В настоящее время у меня есть это в сценарии bash (в цикле for, где $ x - имя файла), чтобы суммировать столбцы по строкам
lines=`grep -v READ $x|wc -l | awk '{print $1}'`
line_num=1
arr_num=0
while [ $line_num -le $lines ]
do
arr[$arr_num]=`grep -v READ $x | sed $line_num'q;d' | awk '{print $2 + $3}'`
echo $line_num
line_num=$[$line_num+1]
arr_num=$[$arr_num+1]
done
Однако в суммируемом файле содержится более 270 000 строк. Сценарий работает уже несколько часов, и он еще далек от завершения. Есть ли более эффективный способ написать это, чтобы это не заняло так много времени?
6 ответов
Вместо этого используйте awk и воспользуйтесь преимуществом модуля функция:
awk '!(NR%2){print $1+$2}' infile
awk
, вероятно, быстрее, но идиоматический bash a> способ сделать это примерно так:
while read -a line; do # read each line one-by-one, into an array
# use arithmetic expansion to add col 1 and 2
echo "$(( ${line[0]} + ${line[1]} ))"
done < <(grep -v READ input.txt)
Обратите внимание, что входной файл файла читается только один раз (grep
), а количество программ, разветвленных извне, сведено к минимуму (только grep
, вызывается только один раз для всего входного файла). Остальные команды являются встроенными bash
.
Использование подстановки процесса <( )
в случае, если переменные, установленные в цикле while, требуются за пределами цикла while. В противном случае можно использовать канал |
.
Ваш вопрос довольно многословный, но ваша цель не ясна. Насколько я понимаю, ваши числа находятся на каждой второй строке, и вы хотите найти только максимальную сумму. Учитывая, что:
awk '
NR%2 == 1 {next}
NR == 2 {max = $1+$2; next}
$1+$2 > max {max = $1+$2}
END {print max}
' filename
Вы также можете использовать конвейер с инструментами, которые неявно перебирают ввод, например:
grep -v read INFILE | tr -s ' ' + | bc | sort -rn | head -1 > OUTFILE
Предполагается, что между вашими значениями данных чтения и записи есть пробелы.
Почему бы не бежать:
awk 'NR==1 { print "sum"; next } { print $1 + $2 }'
Вы можете позволить себе запустить его в файле, пока другой скрипт все еще работает. Это будет сделано максимум за несколько секунд (прогноз). Когда вы уверены, что это правильно, вы можете убить другой процесс.
Вы можете использовать Perl или Python вместо awk
, если хотите.
Ваш код запускает grep
, sed
и awk
в каждой строке входного файла; это чертовски дорого. И это даже не запись данных в файл; он создает массив в памяти Bash, который позже нужно будет распечатать в выходной файл.
Предполагая, что это всегда одна строка заголовка, за которой следует одна строка данных:
awk '
BEGIN{ max = 0 }
{
if( NR%2 == 0 ){
sum = $1 + $2;
if( sum > max ) { max = sum }
}
}
END{ print max }' input.txt
Или просто вырежьте все строки, которые не соответствуют тому, что вы хотите:
grep '^[0-9]\+\s\+[0-9]\+$' input.txt | awk '
BEGIN{ max = 0 }
{
sum = $1 + $2;
if( sum > max ) { max = sum }
}
END{ print max }' input.txt
Похожие вопросы
Новые вопросы
bash
Этот тег предназначен для вопросов о сценариях, написанных для командной оболочки Bash. Сценарии оболочки с синтаксисом или другими ошибками, пожалуйста, проверьте их на https://shellcheck.net, прежде чем публиковать здесь. Вопросы об интерактивном использовании Bash, скорее всего, будут актуальны на Unix & Linux Stack Exchange или Super User, чем на Stack Overflow.
grep
,sed
иawk
для каждой итерации цикла while, вероятно, является основной причиной вашей проблемы с производительностью. Особенно учитывая, чтоgrep
эффективно читает весь файл на каждой итерации.