сравните файлы линию за линией и создайте новый одно программирование удара

Вы выходили из системы и затем входили и пробовали команду?

2
29.09.2015, 23:25
3 ответа

Соединение + вид

При попытке найти IP, которые присутствуют в обоих, можно использовать join команда, но необходимо будет использовать sort предварительно отсортировать файлы до присоединения к ним.

$ join -o 2.2 <(sort file1) <(sort file2)

Пример

$ join -o 2.2 <(sort file1) <(sort file2)
1.765
0.326
4.754
3.673
6.334

Другой пример

файл 1a:

$ cat file1a
34.123.21.32
45.231.43.21
21.34.67.98
1.2.3.4
5.6.7.8
9.10.11.12

файл 2a:

$ cat file2a
34.123.21.32 0.326 - [30/Oct/2013:06:00:06 +0200]
45.231.43.21 6.334 - [30/Oct/2013:06:00:06 +0200]
45.231.43.21  3.673 - [30/Oct/2013:06:00:06 +0200]
34.123.21.32 4.754 - [30/Oct/2013:06:00:06 +0200]
21.34.67.98 1.765 - [30/Oct/2013:06:00:06 +0200]
1.2.3.4 1.234 - [30/Oct/2013:06:00:06 +0200]
4.3.2.1 4.321 - [30/Oct/2013:06:00:06 +0200]

Выполнение join команда:

$ join -o 2.2 <(sort file1) <(sort file2)
1.234
1.765
0.326
4.754
3.673
6.334

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

grep

Можно использовать grep искать соответствия в file2 использование выравнивает, которые находятся в file1, но этот способ не так эффективен как первый метод, который я показал Вам. Это сканирует file2 поиск каждой строки в file1.

$ grep -f file1 file2 | awk '{print $2}'

Пример

$ grep -f file1 file2 | awk '{print $2}'
0.326
6.334
3.673
4.754
1.765
1.234

Улучшающий производительности grep

Можно убыстриться grepпроизводительность при помощи этой формы:

$ LC_ALL=C grep -f file1 file2 | awk '{print $2}'

Можно также сказать grep то, что жала в file1 фиксированная длина (-F) который также поможет в выполнении улучшения.

$ LC_ALL=C grep -Ff file1 file2 | awk '{print $2}'

Обычно в программном обеспечении, Вы стараетесь не иметь необходимость сделать этот подход, хотя, так как это - в основном цикл в типе цикла решения. Но существуют времена, когда лучше, чтобы мог быть достигнут с помощью компьютера + программное обеспечение.

Ссылки

3
27.01.2020, 21:54
  • 1
    спасибо за решение, но результаты не верен. Я имею в виду; строка file1 1:34.123.21.32, я хочу искать этот IP все строки в file2. И я хочу искать весь ıps один за другим в файле 1 в file2 и результатах записи новый файл. –  DessCnk 05.11.2013, 14:35
  • 2
    Вы хотите искать каждый IP в file1 для всех случаев его в file2, да? Это решение делает его, но это сортирует файлы так, чтобы они были в порядке, и затем вытаскивание результатов для соответствий, необходимо ли сохранить их в первоначальном заказе? Подход, который я делаю, является более эффективным b/c, это не должно сохранять повторное сканирование файлом для соответствий, он только должен просканировать одно время! –  slm♦ 05.11.2013, 15:04
  • 3
    @user50591 справки - видят обновления, я добавил 2-й метод, который использует grep и объяснил, что это - недостатки. Также добавленная дополнительная информация, которая, надо надеяться, объясняет, почему соединение + вид является самым быстрым методом. –  slm♦ 05.11.2013, 15:26
  • 4
    большое спасибо slm. Notw это в порядке и работает более эффективное. Я редактирую все свои сценарии и хорошо! –  DessCnk 05.11.2013, 15:33
  • 5
    я думал бы это grep -f достаточно умно для прохождения через файла только однажды. Я признаю ошибку. –  Joseph R. 05.11.2013, 16:17

Можно сказать grep получить его шаблоны из файла с помощью -f переключатель (который находится в стандарте POSIX):

sort file1 | uniq \            # Avoid duplicate entries in file1
 | grep -f /dev/stdin file2 \  # Search in file2 for patterns piped on stdin
 | awk '{print $2}' \          # Print the second field (time) for matches
   > new_file                  # Redirect output to a new file

Обратите внимание на это, если один IP-адрес появляется многократно в file2, все его записи времени будут распечатаны.

Это сделало задание меньше чем за 2 секунды на 5 файлах миллионлайн в моей системе.

2
27.01.2020, 21:54
  • 1
    Спасибо за Ваше предложение, но это использование команды ЦП %99,7 и время процесса является слишком длинным. –  DessCnk 05.11.2013, 11:02
  • 2
    @user50591, Насколько большой file1? Кроме того, Вы попробовали ответ slm? –  Joseph R. 05.11.2013, 13:31
  • 3
    Thaks много, file1 размер является 488K, и я попробую ответ slm теперь. –  DessCnk 05.11.2013, 14:13

Поскольку Вы назвали свое программирование удара вопроса, я отправлю полу пример удара.

Чистый удар:

Вы могли считать IP файл фильтра и затем проверить линию за линией и соответствовать ему против них. Но на этом объеме действительно замедляются.

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

вид + удар:

Другая опция состояла бы в том, чтобы отсортировать файл с sort и обработайте вход, внутренний, например, двоичный поиск. Это, также, было бы намного медленнее затем другие предложения, отправленные здесь, но давайте дадим ему попытку.


Во-первых это - вопрос о версии удара. Версией 4(?) мы имеем mapfile который читает файл для выстраивания. Это намного быстрее затем традиционное read -ra …. Объединенный с sort это могло быть задано сценарием чем-то как (для этой задачи):

mapfile arr <<< "$(sort -bk1,1 "$file_in")"

Затем это - вопрос о наличии алгоритма поиска для нахождения соответствий в этом массиве. Простой путь мог состоять в том, чтобы использовать двоичный поиск. Это эффективно и на, например, массив 1 000 000 элементов дал бы довольно быстрый поиск.

declare -i match_index
function in_array_bs()
{
    local needle="$1"
    local -i max=$arr_len
    local -i min=0
    local -i mid
    while ((min < max)); do
        (( (mid = ((min + max) >> 1)) < max )) || break
        if [[ "${arr[mid]// *}" < "$needle" ]]; then
            ((min = mid + 1))
        else
            max=$mid
        fi
    done
    if [[ "$min" == "$max" && "${arr[min]// *}" == "$needle" ]]; then
        match_index=$min
        return 0
    fi
    return 1
}

Затем Вы сказали бы:

for x in "${filter[@]}"; do
    if in_array_bs "$x"; then
       … # check match_index+0,+1,+2 etc. to cover duplicates.

Демонстрационный сценарий. (Не отлаженный), но просто как начинающий. Для пониженной громкости, где можно было бы хотеть только зависеть от sort, это мог быть шаблон. Но снова s.l.o.w.e.r. b.y a. l.o.t.:

#!/bin/bash

file_in="file_data"
file_srch="file_filter"

declare -a arr       # The entire data file as array.
declare -i arr_len   # The length of "arr".
declare -i index     # Matching index, if any.

# Time print helper function for debug.
function prnt_ts() { date +"%H:%M:%S.%N"; }

# Binary search.
function in_array_bs()
{
    local needle="$1"
    local -i max=$arr_len
    local -i min=0
    local -i mid
    while ((min < max)); do
        (( (mid = ((min + max) >> 1)) < max )) || break
        if [[ "${arr[mid]// *}" < "$needle" ]]; then
            ((min = mid + 1))
        else
            max=$mid
        fi
    done
    if [[ "$min" == "$max" && "${arr[min]// *}" == "$needle" ]]; then
        index=$min
        return 0
    fi
    return 1
}

# Search.
# "index" is set to matching index in "arr" by `in_array_bs()`.
re='^[^ ]+ +([^ ]+)'
function search()
{
    if in_array_bs "$1"; then
        while [[ "${arr[index]// *}" == "$1" ]]; do
            [[ "${arr[index]}" =~ $re ]]
            printf "%s\n" "${BASH_REMATCH[1]}"
            ((++index))
        done
    fi
}

sep="--------------------------------------------"
# Timestamp start
ts1=$(date +%s.%N)

# Print debug information
printf "%s\n%s MAP: %s\n%s\n" \
    "$sep" "$(prnt_ts)" "$file_in" "$sep" >&2

# Read sorted file to array.
mapfile arr <<< "$(sort -bk1,1 "$file_in")"

# Print debug information.
printf "%s\n%s MAP DONE\n%s\n" \
    "$sep" "$(prnt_ts)" "$sep" >&2

# Define length of array.
arr_len=${#arr[@]}

# Print time start search
printf "%s\n%s SEARCH BY INPUT: %s\n%s\n" \
    "$sep" "$(prnt_ts)" "$file_srch" "$sep" >&2

# Read filter file.
re_neg_srch='^[ '$'\t'$'\n'']*$'
debug=0
while IFS=$'\n'$'\t'-" " read -r ip time trash; do
    if ! [[ "$ip" =~ $re_neg_srch ]]; then
        ((debug)) && printf "%s\n%s SEARCH: %s\n%s\n" \
            "$sep" "$(prnt_ts)" "$ip" "$sep" >&2
        # Do the search
        search "$ip"
    fi
done < "$file_srch"

# Print time end search
printf "%s\n%s SEARCH DONE\n%s\n" \
    "$sep" "$(prnt_ts)" "$sep" >&2

# Print total time
ts2=$(date +%s.%N)
echo $ts1 $ts2 | awk '{printf "TIME: %f\n", $2 - $1}' >&2
1
27.01.2020, 21:54

Теги

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