С awk
:
awk -F, '$3=="MP"&&$10=="S"&&$5!="MP"{a[$5]+=$12;b[$5]+=$15}
END{for(i in a){print i","a[i]","b[i]}}' file
-F,
устанавливает разделитель на ,
. $ 3 == "MP" && $ 10 == "S" && $ 5! = "MP" {...}
это условие из вопроса
a [5 долларов США] + = 12 долларов США; b [5 долларов США] + = 15 долларов США
заполняет массив a
общим значением 12 долларов США
и массивом b
] на общую сумму 15 долларов
. END {...}
этот блок запускается, когда awk
завершает обработку всех строк.
for (i in a)
] проходит через a
массив print i »,« a [i] »,« b [i]}
печатает значения в двух массивах и их индекс.Результат:
AI,1,0.2
AIR,5,1
BIR,10,2
Спецификация POSIX дает вам пример для этого:
ls | sed -e 's/"/"\\""/g' -e 's/.*/"&"/' | xargs -E '' printf '<%s>\n'
(с именами файлов, представляющими собой произвольные последовательности из байтов (, отличных от /
и NULL )и sed
/ xargs
, ожидающих текста , вам также необходимо исправить локаль на C (, где все не -байты NUL будут действительными символами ), чтобы сделать это надежным (, за исключением xargs
реализаций, которые имеют очень низкий предел максимальной длины аргумента ))
-E ''
необходим для некоторых xargs
реализаций, которые без него понимали бы аргумент _
для обозначения конца ввода (, где echo a _ b | xargs
выводит a
только для примера ).
С GNU xargs
вы можете использовать:
ls | xargs -d '\n' printf '<%s>\n'
GNU xargs
также имеет -0
, который был скопирован несколькими другими реализациями, поэтому:
ls | tr '\n' '\0' | xargs -0 printf '<%s>\n'
немного более портативный.
Все они предполагают, что имена файлов не содержат символов новой строки. Если могут быть имена файлов с символами новой строки, вывод ls
просто не будет обрабатываться после -. Если вы получите:
a
b
Это могут быть либо два файла a
и b
, либо файл с именем a<newline>b
, точно сказать невозможно.
GNU ls
имеет --quoting-style=shell-always
, который делает его вывод однозначным и может обрабатываться после -, но цитирование несовместимо с цитированием, ожидаемым xargs
. xargs
распознают "..."
, \x
и '...'
формы цитирования. Но и "..."
, и '...'
являются сильными кавычками и не могут содержать символы новой строки. (только \
может экранировать символы новой строки для xargs
),так что это несовместимо с цитированием sh, где только '...'
являются сильными кавычками (и могут содержать символы новой строки ), но \<newline>
является продолжением строки -(удаляется )вместо экранированной новой строки.
Вы можете использовать оболочку для разбора этого вывода, а затем вывести его в формате, ожидаемомxargs
:
eval "files=($(ls --quoting-style=shell-always))"
[ "${#files[#]}" -eq 0 ] || printf '%s\0' "${files[@]}" |
xargs -0 printf '<%s>\n'
Чрезвычайно глупо пытаться анализировать вывод команды ls
, который не предназначен для анализадля передачи команды, которая не предназначена для работы с несколькими символами(например: новые строки
и {}
), когда оболочка делает это сама:
set -- *; for f; do echo "<$f>"; done
set -- *
for f
do ls "$f"
done
Или в одной командной строке:
$ set -- *; for f; do echo "<$f>"; done
<name-with-backslash\>
<-name-with-dash-prefix>
<name-with-double-quote">
<name-with-single-quote'>
<name with space>
<safe-name>
<with_a
newline>
Обратите внимание, что вывод работает (и имеет n примеров в качестве последнего имени файла) с символами новой строки.
Или, если количество файлов делает оболочку медленной, используйте find:
$ find ./ -type f -exec echo '<{}>' \;
<./safe-name>
<./with_a
newline>
<./name-with-double-quote">
<./-name-with-dash-prefix>
<./name with space>
<./name-with-single-quote'>
<./name-with-backslash\>
Только учтите, что find обрабатывает все точечные файлы и все подкаталоги иначе, чем оболочка.
Чтобы xargs
понимал параметр ввода -0
null -с разделителями, отправляющая сторона также должна применять нулевой разделитель к отправляемым данным.
В противном случае между ними нет синхронизации.
Одним из вариантов является команда GNU find
, которая может размещать такие разделители:
find. -maxdepth 1 ! -name. -print0 | xargs -0 ls -ld
Как вы сказали, xargs
не любит непарные двойные кавычки, если только вы не используете -0
, но -0
имеет смысл только в том случае, если вы подаете ему нулевые -завершающиеся данные. Итак, это не удается:
$ echo * | xargs
xargs: unmatched double quote; by default quotes are special to xargs unless you use the -0 option
name-with-backslash -name-with-dash-prefix
Но это работает:
$ printf '%s\0' -- * | xargs -0
-- name-with-backslash\ -name-with-dash-prefix name-with-double-quote" name-with-single-quote' name with space safe-name
В любом случае, ваш базовый подход — не лучший способ сделать это. Вместо того, чтобы возиться с xargs
и ls
и еще чем-то, просто используйте шелл-глобы:
$ for f in *; do ls -l -- "$f"; done
-rw-r--r-- 1 terdon terdon 4142 Aug 11 16:03 a
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 'name-with-backslash\'
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 -name-with-dash-prefix
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 'name-with-double-quote"'
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 "name-with-single-quote'"
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 'name with space'
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 safe-name