Я нашел эту статью, которая может помочь вам смонтировать общие ресурсы SMB.
Я полагаю, что проблема связана с Kerberos, и Себастьян Старк отлично объясняет, что именно я хотел бы сказать.
awk -F':?(Header|Detail)Segment:' '
{ sumPos=10;
for(i=3; i<=NF; i++) {
split($i, tmp, ":")
for(x in tmp) {
sum+=tmp[sumPos]; sumPos+=5
};
gsub(/:|:SubSegment.*/, ",", $i)
gsub(/:/, ",", $2)
printf("%s,%s%.3d\n", $2, $i, sum)
sum=0
};
}' infile
Вы упомянули «учиться», так что вот довольно простой awk-скрипт, который, я думаю, решит вашу проблему. он не оптимизирован ни по скорости, ни по длине кода, но, надеюсь, читаем. Я постараюсь объяснить части, чтобы вы могли извлечь из этого уроки.
вот кодез:
BEGIN {
FS=":"
OFS=","
}
{
pos=readheader()
sanitycheck(pos)
printresult()
}
func readheader() {
r["a"]=$2
r["b"]=$3
r["c"]=$4
r["d"]=$5
r["e"]=$6
pos=7
dcount=0
while($(pos) == "DetailSegment") {
pos=readdetail(pos+1, dcount)
dcount++
}
return pos
}
func readdetail(pos, dcount) {
r["detail"][dcount]["a"]=$(pos+0)
r["detail"][dcount]["b"]=$(pos+1)
r["detail"][dcount]["c"]=$(pos+2)
r["detail"][dcount]["d"]=$(pos+3)
r["detail"][dcount]["e"]=$(pos+4)
r["detail"][dcount]["f"]=$(pos+5)
r["detail"][dcount]["g"]=$(pos+6)
r["detail"][dcount]["h"]=$(pos+7)
pos=pos+8
scount=0
while($(pos) == "SubSegment") {
pos=readsub(pos+1, dcount, scount)
scount++
}
return pos
}
func readsub(pos, dcount, scount) {
r["detail"][dcount]["sub"][scount]["a"]=$(pos+0)
r["detail"][dcount]["sub"][scount]["b"]=$(pos+1)
r["detail"][dcount]["sub"][scount]["c"]=$(pos+2)
r["detail"][dcount]["sub"][scount]["d"]=$(pos+3)
return pos+4
}
func sanitycheck(pos) {
if (pos <= NF) {
print "error line "NR" only parsed "pos" of "NF" fields"
}
}
func printresult() {
for(d in r["detail"]) {
subsum=0
for(s in r["detail"][d]["sub"]) {
subsum+=r["detail"][d]["sub"][s]["a"]
}
print r["a"],r["e"],r["detail"][d]["a"],r["detail"][d]["h"],subsum
}
}
сохраните это в файле с именем filter.awk
.и поместите ввод в файл с именем input
и введите команду
$ awk -f filter.awk input
или направьте вход из источника
$ fromwherecomesinput | awk -f filter.awk
это результат обработки трех строк образцов, которые вы предоставили
1234,29,123467,Purchased,64
1234,29,123468,Refund,0
1234,29,234569,Purchased,0
1234,29,201754,Purchased,0
1234,28,55555,Refund,0
1234,28,123468,Refund,0
1234,28,234569,Purchased,0
1234,28,201754,Purchased,0
1234,28,55555,Sale,56257
1234,28,123468,Refund,0
1234,28,234569,Purchased,0
1234,28,201754,Purchased,0
я не вывел все поля. мне было лень их все печатать.
Я не уверен, правильно ли я понял ваше требование к выводу. возможно, я ошибся. но я пытаюсь объяснить код, поэтому, если вы понимаете остальные коды, вы можете изменить функцию вывода по своему усмотрению.
если строка неправильно сформирована, она выведет что-то вроде этого:
error line 3 only parsed 7 of 20 fields
кроме этой строки вывода отладки, я не делал никакого другого кода для обработки ошибок и создания отчетов.
расшифровка кода:
сначала небольшой обзор того, что делает код :awk считывает ввод построчно. каждая строка разбивается на двоеточие. затем мы перебираем поля и ищем сегменты. затем мы собираем данные в древовидную структуру. наконец, мы перебираем дерево и вычисляем желаемый результат.
К счастью, все сегменты имеют фиксированное количество полей. это делает поиск сегментов очень простым.
древовидная структура примерно такая :в корне есть пять переменных заголовка и список деталей. в каждой детали есть восемь переменных деталей и список подпрограмм. в каждом подразделе есть четыре подварианта.
в конце я связал кучу соответствующих страниц из руководства Fine awk. поэтому, если вы хотите узнать больше о какой-то теме, посмотрите в конце.
приступим к подробному объяснению
BEGIN {
FS=":"
OFS=","
}
блок BEGIN
выполняется awk перед чтением первой строки из ввода. в основном он используется для инициализации переменных.
также есть блок END
, который будет выполняться после прочтения последней строки. он обычно используется для печати конечных результатов.в нашем случае у нас есть результат на строку, но нет кумулятивного конечного результата, поэтому у нас нет блока END
.
FS
— разделитель полей. это говорит awk, как разделить каждую строку ввода на так называемые поля. это одна из основных сильных сторон awk. часто подходящее значение разделителя полей составляет половину решения. в этом случае мы устанавливаем разделитель полей на двоеточие(:
).
OFS
— разделитель выходных полей. это будет символ между полями в операторе печати. в этом случае мы устанавливаем запятую(,
).
Эти переменные называются управляющими, потому что они изменяют работу awk.
Далее следует кодовый блок "для каждой строки"
{
pos=readheader()
sanitycheck(pos)
printresult()
}
этот блок кода будет выполняться для каждой строки (для каждой записи в терминах awk ). я извлек код в функции, так что этот блок короткий и приятный.
(обратите внимание, что вы также можете изменить разделитель записей на что-то другое, кроме новой строки, и тогда запись может быть больше или меньше строки ввода.)
обратите внимание, что в awk все переменные являются глобальными (даже над блоками кода ), поэтому функции в основном предназначены только для структуры для людей. вот почему printresult()
может распечатать результат без передачи каких-либо данных. он просто печатает результат из глобальных переменных. возвращение pos
из readheader()
также не является строго обязательным, поскольку оно является глобальным, но мне понравилось, поэтому я оставил его.
обратите внимание также, что в awk есть только два типа переменных :строки и числа (и массивы ). преобразование является неявным. неинициализированные переменные всегда равны нулю или пустой строке. это чрезмерное упрощение. прочитайте руководства, связанные в конце.
блоки кода часто имеют префикс. например
/foo/ {... }
или
NR > 1 {... }
это условия. это означает, что блок будет выполняться только в том случае, если текущая запись удовлетворяет условию.
наш блок кода не имеет такого условия, поэтому он выполняется для каждой строки.
На жаргоне awk условие называется шаблоном, а блоки кода — действиями.
следующее объяснение функций:
func readheader() {
r["a"]=$2
r["b"]=$3
r["c"]=$4
r["d"]=$5
r["e"]=$6
pos=7
dcount=0
while($(pos) == "DetailSegment") {
pos=readdetail(pos+1, dcount)
dcount++
}
return pos
}
здесь код начинает выглядеть как обычный язык программирования. помните, что эта функция вызывается из блока «для каждой строки». поэтому эта функция вызывается один раз на строку.
$2
и другие цифры доллара являются ссылками на поля. поля - это части строки после того, как awk выполнил разбиение. в нашем случае поля — это значения между двоеточиями.
($
в awk используется только для переменных поля. и в регулярных выражениях, где они имеют совершенно другое значение, но это совсем другая история. у нас нет регулярных выражений в этом коде, поэтому ничего из этого здесь)
$0
— это всегда вся строка.
$1
в нашем случае всегда будет HeaderSegment
, поэтому мы просто пропускаем это (без проверки ошибок ). От $2
до $6
— пять значений HeaderSegment
.
мы храним эти переменные в массиве с именем r
. короткое имя опасно, потому что все глобально, но нам очень нужна эта переменная, а я ленив, поэтому взял короткое имя.
Массивы в awk — это не массивы, как в c или java, а скорее карты или словари. сопоставление ключевых значений. ключи могут быть любой строкой или числом. если повторяться, то порядок в основном случайный. значения могут быть любыми, включая другие массивы. этот массив массивов - это то, что мы используем для построения дерева.
Я использовал клавиши с "a"
по "e"
, потому что у меня нет лучших имен для значений. вы знаете семантическое значение значений и можете дать им более осмысленные имена, такие как "customerID"
или "froobazzaloopaCount"
.
$(pos)
— вычисляемая или косвенная полевая переменная. сначала оценивается часть в скобках. то поле ссылается. поэтому, если pos
равно 7
, тогда $(pos)
равно $7
и $(pos+1)
равно $8
.это особенно интересно, если зацикливаться на поле, как мы делаем здесь, ищем следующий DetailSegment
.
На жаргоне awk это называется непостоянными номерами полей.
остальные функции(readdetail
иreadsub
)работают аналогично.
функция sanitycheck
:
func sanitycheck(pos) {
if (pos <= NF) {
print "error line "NR" only parsed "pos" of "NF" fields"
}
}
NF
— количество полей в этой записи. pos
— это переменная, которую мы использовали, чтобы отслеживать, какое поле мы рассмотрим следующим. поэтому, если pos
меньше NF
, что-то не так. тогда мы сообщаем об ошибке.
NR
— номер текущей записи. поскольку в нашем случае запись в основном представляет собой строку, это номер строки.
Эти переменные называются информационными, потому что они дают информацию о текущем состоянии awk.
функция результатов печати:
func printresult() {
for(d in r["detail"]) {
subsum=0
for(s in r["detail"][d]["sub"]) {
subsum+=r["detail"][d]["sub"][s]["a"]
}
print r["a"],r["e"],r["detail"][d]["a"],r["detail"][d]["h"],subsum
}
}
Никаких больших сюрпризов. это работает, как и большинство современных языков. for(d in r["detail"])
перебирает ключи в массиве r["detail"]
. первый цикл перебирает детали. второй цикл перебирает сабвуферы в детали.
для каждой детали выведите числа и сумму первого значения в подпунктах.
одно замечание по поводу print
утверждения:
у нас здесьprint 1,2,3
(разделены запятой )и вывод1,2,3
(разделены запятой ). это потому, что у насOFS
(разделитель полей вывода )установлен в запятую. если OFS
было, например, #
, тогда print 1,2,3
выведет 1#2#3
.
примечаниеprint "1,2,3"
(в кавычках )всегда будет 1,2,3
независимо от OFS
, потому что на этот раз запятая является буквальной запятой.
Надеюсь, это помогло вам понять, как решить вашу проблему с помощью awk. надеюсь, я также смог объяснить вещи достаточно хорошо, чтобы вы могли адаптировать код к своим дальнейшим потребностям.
ссылки на связанные темы в руководстве Fine awk
подробнее о блоках BEGIN
и END
:https://www.gnu.org/software/gawk/manual/html_node/Using-BEGIN_002fEND.html
подробнее о разделителе полей(FS
):https://www.gnu.org/software/gawk/manual/html_node/Field-Separators.html
подробнее об «управляющих» переменных (FS
, OFS
и др.):https://www.gnu.org/software/gawk/manual/html_node/User_002dmodified.html
подробнее о "информационных" переменных(NR
иNF
):https://www.gnu.org/software/gawk/manual/html_node/Auto_002dset.html
подробнее о записях (, которые чаще всего являются строками):https://www.gnu.org/software/gawk/manual/html_node/Records.html
подробнее о видимости переменных (все глобально ):https://www.gnu.org/software/gawk/manual/html_node/Global-Namespace.html, но некоторые могут быть локальнымиhttps://www.gnu.org/software/gawk/manual/html_node/Variable-Scope.html
подробнее о типах переменных (строки и числа):https://www.gnu.org/software/gawk/manual/html_node/Variable-Typing.html
подробнее о шаблонах и действиях (условия и блоки кода):https://www.gnu.org/software/gawk/manual/html_node/Patterns-and-Actions.html
подробнее о массивах (карты ключ-значение или словари):https://www.gnu.org/software/gawk/manual/html_node/Arrays.html
подробнее о номерах полей (числовое значение в долларах или переменные поля):https://www.gnu.org/software/gawk/manual/html_node/Fields.html
подробнее о непостоянных номерах полей (вычисляемые или косвенные переменные поля):https://www.gnu.org/software/gawk/manual/html_node/Nonconstant-Fields.html