Агрегат и текстовый файл группы в жемчуге или ударе

От удара (1):

ПСЕВДОНИМЫ

[...] первое слово каждой простой команды, если закрывшийся кавычки, проверяется, чтобы видеть, имеет ли это псевдоним [...] символы [...] и любой из метасимволов оболочки или упомянутых выше символов заключения в кавычки не могут появиться на имя псевдонима.

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

Использование обоих -f и -i в вызове к комнате также не имеет большого смысла, потому что они являются несколько противоречащими (комната (1)):

- f, - сила игнорирует несуществующие файлы и аргументы, никогда не запрашивает

- я запрашиваю перед каждым удалением

Но вот хорошая вещь - Ваш псевдоним к rm на самом деле используется, даже когда Вы звоните rm -r, потому что первое слово - rm - имеет псевдоним - rm -i, таким образом, это заменяется этим!

$ alias rm
bash: alias: rm: not found
$ alias rm='rm -i'
$ mkdir test
$ rm -r test
rm: remove directory ‘test’?

/ редактирование: Raphael Ahrens также упомянул в комментариях то использование -f (сила) не необходима для удаления каталогов (как может быть уже замечен в моем примере), -r достаточно (рекурсивный) является одним:

- r,-R, - рекурсивный удаляют каталоги и их содержание рекурсивно

3
11.01.2015, 06:32
4 ответа

In Perl

perl -F';' -lane 'push @{$h{join ";",@F[0..2]}},$F[3];
                  END{
                    for(sort keys %h){
                        print "$_: ". join ",",@{$h{$_}};
                    }
                  }' your_file

Вы должны уметь делать что-то подобное в awk, используя ассоциативные массивы, но я не очень хорошо разбираюсь в awk, так что я не могу внести реальный код.

Объяснение

Вот расширенная версия вышеуказанного кода, использующая как можно меньше "магии":

open($FH,"<","your_file");
while($line=<$FH>){ # For each line in the file (accomplished by -n)
    chomp $line; # Remove the newline at the end (done by -l)
    # The ; is set by -F and storing the split in @F done by -a
    @F = split /;/,$line # Split the line into fields on ;
    $app_id = join ";",@F[0..2]; # AppID is the first 3 fields
    push @{$h{$app_id}},$F[3]; # The 4th field is added onto the hash
} # The whole file has been read at this point.
foreach $key (sort keys %h){ # Sort the hash by AppID
     print "$key: " . join ",",@{h{$key}}."\n"; # Print the array values
     # The newline ("\n") added at the end is also done by -l
}

Теперь осталось только утверждение push, чтобы объяснить более подробно:

  • push обычно используется для добавления элементов в переменную массива. Например:

    push @a,$x
    

    добавляет содержимое переменной $x в массив @a.

  • Цикл чтения файла построчно заполняет хэш-таблицу (%h). Ключами к хэшу являются AppIDs, а значение, соответствующее каждому ключу, представляет собой массив, содержащий все идентификаторы пользователей, связанные с этим AppID. Это анонимный массив (у него нет имени); в Perl это реализовано в виде ссылки на массив (несколько похоже на указатели C). А так как значение %h, соответствующее AppID $app_id обозначается $h{$app_id}, то при обращении к сигиальному массиву Perl (@) хэш-значение рассматривается как массив (отсылка к ссылке на массив) и на него нажимается текущий идентификатор пользователя.

  • Альтернативой, которая может показаться вам менее "Perlish", будет соединение 4-го поля с текущим значением:

    while(...) { ... $h{$app_id} = $h{$app_id} . ",$F[3]" }
    foreach $key (клавиши сортировки %h) { распечатать "$_: $h{$_}") }
    

    , где . в Perl является оператором конкатенирования строк.

Обратите внимание, что в коде объяснения я опустил обертку perl -e '...', чтобы подсветка синтаксиса могла попасть в код и сделать его более читабельным.

.
3
27.01.2020, 21:11

Ответ: sed:

sed ': l;N;s/^\([^;]\+;[^;]\+;[^;:]\+\)[;:] *\(.*\)\n\1;\(.*\)/\1: \2, \3/;tl;P;D' input_file.txt

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

С подробностями:

sed ': l;        # Label l

     N;          # Add next line of input to pattern space

     s/^\([^;]\+;[^;]\+;[^;:]\+\)[;:] *\(.*\)\n\1;\(.*\)/\1: \2, \3/;
                 # If two lines in pattern space start with same AppID, then
                 # take user ID and append it to first line, then delete second line

         tl;     # If previous substitution succeeded, i.e. we scanned two lines with 
                 # same AppID, then loop to label l. Else go on…

     P;          # Print first line from pattern space (here there should be two lines
                 # in pattern space, starting with a different AppID)

     D;          # Delete first line of pattern space; start script again with
                 # remaining text in pattern space, or next input line if pattern
                 # space is empty
    ' input_file.txt

(Но я понятия не имею о потенциальных ограничениях длины строк, извините.)

1
27.01.2020, 21:11

Поскольку вы утверждаете, что файл отсортирован, не следует ли использовать простой цикл с памятью только для предыдущей строки appId? Это похоже на подход @Qeole sed, но позволяет избежать накладных расходов на регулярные выражения, используя функцию shell's delimited read plus string comparison:

#!/bin/bash

appId=""

while IFS=\; read -r s1 s2 s3 userId; do
  if [ "$s1;$s2;$s3" == "$appId" ]; then
    printf ', %s' "$userId"
  else
    appId="$s1;$s2;$s3"
    printf '\n%s:%s' "$appId" "$userId"
  fi
done < yourfile
printf '\n'

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

2
27.01.2020, 21:11

Вот AWK решение:

awk '10<=NR && NR<=15 && /pattern/ {print NR,$0}' file

Если мы должны использовать только SED , затем рассмотрим:

sed -n '10,15 {/pattern/ {=;p}}' file | sed 'N;s/\n/ /'

SED = Команда будет печатать только номер строки на отдельной строке. Второй случай SED выше используется для объединения каждых двух линий, чтобы номер линии отображался незадолго до его линии.

-121--125640-

С SED :

sed 's/;/:\t/3;H;1h;x                                                                                        
s/^\(\([^:]*\):.*\)\n\2/\1/                                                                                      
/\n/P;//g;h;$!d' <input |
tr : \\n

, что печатается:

44a934ca4052b34e70f9cb03f3399c6f065becd0;bf038823f9633d25034220b9f10b68dd8c16d867;309
        8ead5b3e0af5b948a6b09916bd271f18fe2678aa
        a21245497cd0520818f8b14d6e405040f2fa8bc0
5c3eb56d91a77d6ee5217009732ff421e378f298;200000000000000001000000200000,6fd299187a5c347fe7eaab516aca72295faac2ad,e25ba62bbd53a72beb39619f309a06386dd381d035de372c85d70176c339d6f4;16
        337556fc485cd094684a72ed01536030bdfae5bb
        382f3aaa9a0347d3af9b35642d09421f9221ef7d
        396529e08c6f8a98a327ee28c38baaf5e7846d14

Вы можете отбрасывать TR , чтобы сохранить группы на одной линии. ID ID : : толстой кишки в этом случае. Вам также может потребоваться заменить \ T \ T в первой строке с литералом символ - или вы можете не стесняться удалить \ T ABS полностью - они служат только для того, чтобы сделать выпуск более читаемым (на мой взгляд) и не имеет жизненно важной для функции регулярного воздействия.

2
27.01.2020, 21:11

Теги

Похожие вопросы