Отображение отформатированных записей с использованием AWK - PullRequest
0 голосов
/ 05 марта 2019

Я дал входной файл, где он выглядит так:

ID          PID   PPID   C STIME  TTY            TIME  CMD
adz110     5344   5334   0 08:47  pts/2     00:00:00  bash
dmq292     6908   6854   0 08:53  pts/1     00:00:00  bash
adz110     7227   7150   0 08:54  pts/9     00:00:00  who
erg474     7466   7461   0 08:54  pts/10    00:00:00  ls
dmq292     7966   7960   0 08:55  pts/13    00:00:00  assign1.sh if of
xle135     8636   8628   0 08:58  pts/15    00:00:00  bash
xle135     8983   8636   0 08:59  pts/15    00:00:00  ssh ctf.cs.utsarr.net
zeh458     9057   1980   0 08:59  pts/7     00:00:00  vim prog.c
HanSolo    9150   9139   0 08:59  pts/16    00:00:00  ps -af

, и он должен заканчиваться так:

User: adz110
    bash
    who
User: dmq292
    bash
    assign1.sh if of
User: erg474
    ls
User: xle135
    bash
    ssh ctf.cs.utsarr.net
User: zeh458
    vim prog.c
Earliest  Start  Time:
adz110    5344   5334 0 08:47  pts/2     00:00:00  bash

Latest  Start  Time
xle135    8983   8636   0 08:59  pts /15    00:00:00  ssh ctf.cs.utsarr.net

То, что я до сих пор придумывал, таково:в файле file.awk, который я записал:

/[a-z]{3}[0-9]{3}/    
{   
    print $1
    if( match($1 , arg1) )
    {
    for(i=8; i <= NF ; i ++) 

       printf("%s", $i); 

    printf("\n"); 

    }

}
END {
        print " Earliest Start Time:" 

        print "Latest Start Time: "
 }

Таким образом, вместо печати для каждого пользователя, имя пользователя которого совпадает с [az] [0-9] {3}, он печатает cmd вместе симя пользователя без пробелов.У меня много проблем с пониманием ассоциативных массивов и использованием специальных переменных, таких как NR, RS и т. Д.

Ответы [ 4 ]

0 голосов
/ 05 марта 2019

Предполагая, что если данный пользователь запускает одну и ту же команду несколько раз, вы хотите, чтобы эта команда несколько раз появлялась в выходных данных для этого пользователя:

$ cat tst.awk
NR == 1 { next }
/^[a-z]{3}[0-9]{3}/ {
    user = $1
    users[user]

    cmd = $0
    sub(/([^[:space:]]+[[:space:]]+){7}/,"",cmd)
    cmds[user,++numCmds[user]] = cmd

    stime = $5
    if ( (earliestStime == "") || (stime < earliestStime) ) {
        earliestStime = stime
        earliestData  = $0
    }
    if ( (latestStime == "") || (stime > latestStime) ) {
        latestStime = stime
        latestData  = $0
    }
}
END {
    for (user in users) {
        printf "User: %s\n", user
        for (cmdNr=1; cmdNr<=numCmds[user]; cmdNr++) {
            printf "   %s\n", cmds[user,cmdNr]
        }
    }

    print "\nEarliest  Start  Time:"
    print earliestData

    print "\nLatest  Start  Time:"
    print latestData
}

.

$ awk -f tst.awk file
User: xle135
   bash
   ssh ctf.cs.utsarr.net
User: zeh458
   vim prog.c
User: dmq292
   bash
   assign1.sh if of
User: erg474
   ls
User: adz110
   bash
   who

Earliest  Start  Time:
adz110     5344   5334   0 08:47  pts/2     00:00:00  bash

Latest  Start  Time:
xle135     8983   8636   0 08:59  pts/15    00:00:00  ssh ctf.cs.utsarr.net

Если порядок пользователей или команд в выходных данных имеет значение, то сообщите нам, какой должен быть порядок, и его будет достаточно легко адаптировать, например, сохранив порядок ввода или установив PROCINFO["sorted_in"] с помощью GNU awk перед каждым циклом в разделе END..

0 голосов
/ 05 марта 2019

Во входном файле есть одна путаница (выходные данные вашей команды отображают несколько процессов с одинаковым временем, например, xle135 и zeh458).Таким образом, решение, которое я придумала, будет сортировать ваш входной файл (вы можете поместить свою команду, если вам нужно, вместо него тоже), тогда он определит максимальный и минимальный период времени из всех записей.Если некоторые вещи имеют одинаковую отметку времени, не объединит их значения (хотя мы могли бы это сделать тоже);вместо этого он напечатает последний отсортированный (только с последней отметкой времени).

awk '
/^ID/{
  next
}
{
  split($5,array,":")
  seconds=array[1]*60+array[2]
}
FNR==NR{
  a[$1]++
  tim[seconds]=$0
  next
}
a[$1]==2{
  print "User: " $1  ORS "    " $NF
  getline
  sub(/.*:00/,"")
  print"  " $0
}
a[$1]==1{
  val=$0
  sub(/.*:00/,"",val)
  print "User: " $1 ORS "    " val
}
{
  min=min<seconds?(min?min:seconds):seconds
  max=max>seconds?max:seconds
}
END{
  print "Earliest  Start  Time:" ORS tim[min] ORS "Latest  Start  Time" ORS tim[max]
}
' <(sort -k1,5 Input_file)  <(sort -k1,5 Input_file)

Вывод будет следующим.

User: adz110
    bash
    who
User: dmq292
    bash
    assign1.sh if of
User: erg474
      ls
User: HanSolo
      ps -af
User: xle135
    bash
    ssh ctf.cs.utsarr.net
User: zeh458
      vim  prog.c
Earliest  Start  Time:
adz110     5344   5334   0 08:47  pts/2     00:00:00  bash
Latest  Start  Time
zeh458     9057   1980   0 08:59  pts/7     00:00:00  vim  prog.c
0 голосов
/ 05 марта 2019

Попробуйте, file.awk:

$1 !~ /[a-z]{3}[0-9]{3}/ {next;}
!fstTime {fstTime=$5; lstTime=$5; first=$0; last = $0;}
!($1 in a) {a[$1];users[++ind]=$1;}
{   cmd=$8; for(i=9;i<=NF;i++) cmd=cmd OFS $i;
    cmds[$1] = cmds[$1] ? cmds[$1] "\n    " cmd : "    " cmd;
    if ($5 < fstTime) { fstTime=$5; first=$0; }
    if ($5 > lstTime) { lstTime=$5; last = $0; }
}
END { 
    for(i=1;i<=length(a);i++) {
        print "User: " users[i];
        print cmds[users[i]];
    }
    print "Earliest  Start  Time:\n" first "\n\nLatest  Start  Time:\n" last; 
}

awk -f file.awk fileToTest.txt выход:

User: adz110
    bash
    who
User: dmq292
    bash
    assign1.sh if of
User: erg474
    ls
User: xle135
    bash
    ssh ctf.cs.utsarr.net
User: zeh458
    vim prog.c
Earliest  Start  Time:
adz110     5344   5334   0 08:47  pts/2     00:00:00  bash

Latest  Start  Time:
xle135     8983   8636   0 08:59  pts/15    00:00:00  ssh ctf.cs.utsarr.net

Если вы хотите, чтобы zeh458 9057 1980 0 08:59 pts/7 00:00:00 vim prog.c была строкой Latest Start Time:, просто измените ($5 > lstTime) до ($5 >= lstTime) будет делать.

0 голосов
/ 05 марта 2019

Вы хотите применить регулярное выражение только к первому полю и собрать значения для каждого пользователя в памяти в формате, подходящем для печати. ​​

Обратите внимание, что список имеет фиксированную ширину;поэтому имя и аргументы программы находятся в поле, которое начинается в столбце 55. Аналогично, отметка времени находится в столбцах 28-32.

awk 'NR > 1 && $1 ~ /^[a-z]{3}[0-9]{3}$/ {
  when = substr($0, 28, 5)
  command = substr($0, 55)  
  if ($1 in user) {
      # Append this command to previous value
      user[$1] = user[$1] ORS "    " command
  } else {
      # Create a new item in this associative array
      user[$1] = "    " command
  }
  if (NR==2 || when > max) { max=when; maxcmd = $0 }
  if (NR==2 || when < min) { min=when; mincmd = $0 }
}
END {
    # XXX TODO: sort array?
    for (u in user) printf "User %s:\n%s\n", u, user[u]
    print "Earliest start time"; print mincmd
    print "Lastest start time"; print maxcmd
}' filename

Поэтому, когда мы впервые видим конкретного пользователя, они не будутбыть в users, и поэтому мы просто помещаем их первую команду с отступом в четыре пробела в качестве значения для этого ключа в ассоциативном массиве.Если мы увидим их снова, мы добавим еще одну строку к значению, с новой строкой (ORS) и четырьмя пробелами впереди.

NR - номер текущей строки - мы пропускаем NR==1, чтобыизбегайте захвата строки заголовка, и с помощью NR==2 мы знаем, что это первая строка, которую мы обрабатываем, поэтому мы устанавливаем max и min в их базовые значения.

В идеале, вы также должны нормализоватьвременные метки в канонической форме, так что вы можете отсортировать «вчера 21:24» до «21:23», но я не пойду туда с этим простым ответом.Вы, вероятно, хотите добавить украшения и в других местах.(Или, может быть, вы можете полагаться на тот факт, что входные данные сортируются по времени начала процесса?)

Если вы хотите, чтобы имена пользователей сортировались, в GNU Awk встроена сортировка массива;для других Awks вам нужно написать собственную простую функцию сортировки или использовать внешний конвейер.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...