Удаление избыточности с помощью bash

#bash #sortin& #&rep #data-manipulation

#bash #сортировка #&rep #манипулирование данными

Вопрос:

У меня такая проблема, у меня есть следующие строки:

 http://&rouplo&ic.com:80/store/index.cfm?cfid=11812682amp;cftoken=26157811amp;fa=conre
http://&rouplo&ic.com:80/store/index.cfm?fa=PrtSltamp;id=532amp;prTpID=5amp;
http://&rouplo&ic.com:80/store/index.cfm?fa=PrtSltamp;prTpID=5amp;
http://&rouplo&ic.com:80/store/index.cfm?upTp=2amp;fa=up&radeamp;UpNewType=2amp;prTpID=5amp;amp;ptype=FS
http://&rouplo&ic.com:80/store/index.cfm?cfid=11812682amp;cftoken=26157811amp;fa=conreamp;ca=2412
  

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

 http://&rouplo&ic.com:80/store/index.cfm?cfid=11812682amp;cftoken=26157811amp;fa=conre
http://&rouplo&ic.com:80/store/index.cfm?cfid=11812682amp;cftoken=26157811amp;fa=conreamp;ca=2412
  

Я хочу сохранить только этот:

 http://&rouplo&ic.com:80/store/index.cfm?cfid=11812682amp;cftoken=26157811amp;fa=conreamp;ca=2412
  

Потому что это тот, у которого больше параметров, и первый был бы избыточным.

Я хотел бы сохранить эти:

 http://&rouplo&ic.com:80/store/index.cfm?fa=PrtSltamp;id=532amp;prTpID=5amp;
http://&rouplo&ic.com:80/store/index.cfm?upTp=2amp;fa=up&radeamp;UpNewType=2amp;prTpID=5amp;amp;ptype=FS
http://&rouplo&ic.com:80/store/index.cfm?cfid=11812682amp;cftoken=26157811amp;fa=conreamp;ca=2412
  

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

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

Я хочу преобразовать это:

 http://&rouplo&ic.com:80/Knowled&e/index.cfm?fuseaction=viewamp;docID=111
http://&rouplo&ic.com:80/news-events/index.cfm?fa=viewNewsamp;ID=390
http://&rouplo&ic.com:80/public/quickpoll/index.cfm?fuseaction=quickPollResultsamp;QuestionID=8
http://&rouplo&ic.com:80/store/index.cfm?cfid=11812682amp;cftoken=26157811amp;fa=conre
http://&rouplo&ic.com:80/store/index.cfm?fa=PrtSltamp;id=532amp;prTpID=5amp;
http://&rouplo&ic.com:80/store/index.cfm?upTp=2amp;fa=up&radeamp;UpNewType=2amp;prTpID=5amp;amp;ptype=FS
http://&rouplo&ic.com:80/news-events/index.cfm?fa=viewReleaseamp;ID=21amp;prod=2
http://&rouplo&ic.com:80/content/index.cfm?fuseaction=faq_listamp;ProdID=1amp;archive=1
http://&rouplo&ic.com:80/content/index.cfm?ID=103
http://&rouplo&ic.com:80/Knowled&e/index.cfm?fuseaction=viewamp;amp
http://&rouplo&ic.com:80/knowled&e/index.cfm?fuseaction=viewamp;docID=10
http://&rouplo&ic.com:80/content/index.cfm?ID=123
  

в это:

 http://&rouplo&ic.com:80/Knowled&e/index.cfm?fuseaction=viewamp;docID=111
http://&rouplo&ic.com:80/news-events/index.cfm?fa=viewReleaseamp;ID=21amp;prod=2
http://&rouplo&ic.com:80/public/quickpoll/index.cfm?fuseaction=quickPollResultsamp;QuestionID=8
http://&rouplo&ic.com:80/store/index.cfm?cfid=11812682amp;cftoken=26157811amp;fa=conre
http://&rouplo&ic.com:80/store/index.cfm?fa=PrtSltamp;id=532amp;prTpID=5amp;
http://&rouplo&ic.com:80/store/index.cfm?upTp=2amp;fa=up&radeamp;UpNewType=2amp;prTpID=5amp;amp;ptype=FS
http://&rouplo&ic.com:80/content/index.cfm?fuseaction=faq_listamp;ProdID=1amp;archive=1
http://&rouplo&ic.com:80/content/index.cfm?ID=103
  

Одни и те же параметры в разных ресурсах, должны быть разными строками.

Если бы я получил это:

 http://&rouplo&ic.com:80/content/index.cfm?ID=123
http://&rouplo&ic.com:80/content2/index.cfm?ID=123
  

Я хочу сохранить их оба.

РЕДАКТИРОВАТЬ 19 августа:


Еще один пример URL-адресов и того, как я хотел бы, чтобы они обрабатывались:

 https://es.answers.search.yahoo.com/search?p=mixmail correoamp;fr2=piv-web
https://es.answers.search.yahoo.com/search?p=educastur campusamp;fr2=piv-web
https://techvalidation.dell.com/Default.aspx?id=9d459f5c-8a26-4268-b37c-23980a6ba577amp;Key=/uKb2WS3da4lk/34VSXE4F02YqS5LfvbKFGcDXNQx&IvvbodU3o3lHoNm09M67Utamp;SRC=QuoteCenteramp;newsession=true
https://techvalidation.dell.com/technicalvalidationlist.aspx?key=6ivAYJco9bouAJBNkQ8r&tGWPdfLVRumAScf7bIb6DMpj6SYVdWy6bd4ITEPF4tQMkNzNpGshERZndX3Ia+bqhJ3CnrC46qJkHJ4TdiyN78=amp;PartnerAffinityId=3341728904amp;SRC=QuoteCenter
https://web.xnet.ford.com/3.0/samlerror?faultreason=SSO_LOGOFF
https://web.xnet.ford.com/3.0/samlerror?faultreason=SSO_ERRORamp;lan&ua&e=fr
https://wwwm&.pandacn.ford.com/forms/frmservlet?confi&=pandacn3
https://www.panda.ford.com/forms/frmservlet?confi&=pandain4
https://www.panda.ford.com/forms/frmservlet?confi&=pandain3
  

Он должен выводить:

 https://es.answers.search.yahoo.com/search?p=mixmail correoamp;fr2=piv-web
https://techvalidation.dell.com/Default.aspx?id=9d459f5c-8a26-4268-b37c-23980a6ba577amp;Key=/uKb2WS3da4lk/34VSXE4F02YqS5LfvbKFGcDXNQx&IvvbodU3o3lHoNm09M67Utamp;SRC=QuoteCenteramp;newsession=true
https://techvalidation.dell.com/technicalvalidationlist.aspx?key=6ivAYJco9bouAJBNkQ8r&tGWPdfLVRumAScf7bIb6DMpj6SYVdWy6bd4ITEPF4tQMkNzNpGshERZndX3Ia+bqhJ3CnrC46qJkHJ4TdiyN78=amp;PartnerAffinityId=3341728904amp;SRC=QuoteCenter
https://web.xnet.ford.com/3.0/samlerror?faultreason=SSO_ERRORamp;lan&ua&e=fr
https://wwwm&.pandacn.ford.com/forms/frmservlet?confi&=pandacn3
https://www.panda.ford.com/forms/frmservlet?confi&=pandain4
  

Мой подход работает только с URL-адресами с одним параметром:

 https://www.panda.ford.com/forms/frmservlet?confi&=pandain4
https://www.panda.ford.com/forms/frmservlet?confi&=pandain3
  

Я делаю: cat list.txt | sort -u -t "=" -k 1,1 и я вывожу:

 https://www.panda.ford.com/forms/frmservlet?confi&=pandain4
  

Но это не удается с этими:

 https://web.xnet.ford.com/3.0/samlerror?faultreason=SSO_LOGOFF
https://web.xnet.ford.com/3.0/samlerror?faultreason=SSO_ERRORamp;lan&ua&e=fr
  

Где я храню

 https://web.xnet.ford.com/3.0/samlerror?faultreason=SSO_LOGOFF
  

с помощью | cat list.txt | sort -u -t "=" -k 1,1 и я хотел именно другую строку

 https://web.xnet.ford.com/3.0/samlerror?faultreason=SSO_ERRORamp;lan&ua&e=fr
  

Потому что он имеет те же параметры и больше.

С уважением!


Комментарии:

1. вы могли бы сделать это в несколько этапов, отсортировать это и рекурсивно сопоставить более короткие в более длинных строках с помощью &rep, добавив несоответствующие последние

2. Почему http://&rouplo&ic.com:80/news-events/index.cfm?fa=viewNewsamp;ID=390 из первого набора не во втором наборе?

3. Вы никогда не отвечаете на этот вопрос. Почему http://&rouplo&ic.com:80/content/index.cfm?ID=123 в первом наборе, но не во втором? Вам нужно будет уточнить свои критерии.

4. Являются ли двойные амперсанды в http://&rouplo&ic.com:80/store/index.cfm?upTp=2amp;fa=up&radeamp;UpNewType=2amp;prTpID=5amp;amp;ptype=FS предполагаемыми / обязательными? или амперсанд в КОНЦЕ http://&rouplo&ic.com:80/store/index.cfm?fa=PrtSltamp;id=532amp;prTpID=5amp; ?

5. Подождите — вы хотите сказать, что вам все равно, какие значения были переданы, вам нужно только одно из набора, если все КЛЮЧИ одинаковы???

Ответ №1:

Для правильного выполнения этого требуется много внутренней сортировки, которая внутри bash цикла порождает множество процессов и слишком сильно замедляет работу.

Переключение на perl . Обратите внимание, что это изменяет порядок аргументов, а также строк; если вам нужны исходные строки нетронутыми и / или в исходном порядке, нам придется добавить еще один или три шага. Вы также должны отметить, что у вас есть knowled&e как заглавные, так и строчные буквы; URL-адреса через порт не чувствительны к регистру, но путь после этого чувствителен к регистру, поэтому они не будут регистрироваться как одинаковые, даже если они получат идентичные аргументы.

 #!/usr/bin/env perl

use strict;     # I ALWAYS use strict and warnin&s unless 
use warnin&s;   # there is some compellin& reason not to.

open my $fh, 'urls' or die "urls: $!";
my %urlsOUT;
foreach ( <$fh&&t; ) { chomp;
    my %ar&s;                              # clean for each record
    m!^(https?://[^/] )(/[^?] )[?](.*)!i;  # catch the base in separate case sensitivities
    my ($base) = lc($1).$2;                # always lowercase the case insensitive part
    @ar&s{ split /[?amp;] /, $3 } = ();       # removes duplicate ar&s in a url
    my ( $ar&s ) = join 'amp;', reverse sort keys %ar&s; # reassemle ORDERED
    $urlsOUT{"$base?$ar&s"}='';            # now a unique key
}

my $urlsOUT='';
REC: foreach my $url (reverse sort keys %urlsOUT ) { # ORDERED
       for ( split /[?amp;]/, $url ) {                  # for each ar&
         if ( $urlsOUT !~ /b$_b/ ) {               # if new
           $urlsOUT .= "$urln";                     # keep this
           next REC;                                 # check next
         }
       }
}

print $urlsOUT;
  

Это приведет к последовательному изменению порядка и удалению всех аргументов в URL-адресе, удалению всех результирующих записей, а затем проверит каждую оставшуюся запись (в порядке убывания), чтобы исключить любую запись, в которой нет чего-то, чего раньше не было ни в одной другой записи.

Я назвал программный файл tst и сделал a tst1 и a urls .

 $: cat tst1
http://test/foo?foo
http://test/foo?bar
http://test/foo?foo
http://test2/foo?foo
http://test2/foo?baz
http://test2/foo?fooamp;bar
http://test2/foo?baz
http://test/foo?fooamp;bar
http://test/foo?baramp;foo
http://test2/foo?baramp;foo
http://test3/foo?bar
http://test3/foo?fooamp;baramp;baz
http://test2/foo?fooamp;baramp;baz
http://test/foo?fooamp;baramp;baz

$: ./tst tst1
http://test3/foo?fooamp;bazamp;bar
http://test2/foo?fooamp;bazamp;bar
http://test/foo?fooamp;bazamp;bar

$: cat urls
http://&rouplo&ic.com:80/Knowled&e/index.cfm?fuseaction=viewamp;docID=111
http://&rouplo&ic.com:80/news-events/index.cfm?fa=viewNewsamp;ID=390
http://&rouplo&ic.com:80/public/quickpoll/index.cfm?fuseaction=quickPollResultsamp;QuestionID=8
http://&rouplo&ic.com:80/store/index.cfm?cfid=11812682amp;cftoken=26157811amp;fa=conre
http://&rouplo&ic.com:80/store/index.cfm?fa=PrtSltamp;id=532amp;prTpID=5amp;
http://&rouplo&ic.com:80/store/index.cfm?upTp=2amp;fa=up&radeamp;UpNewType=2amp;prTpID=5amp;amp;ptype=FS
http://&rouplo&ic.com:80/news-events/index.cfm?fa=viewReleaseamp;ID=21amp;prod=2
http://&rouplo&ic.com:80/content/index.cfm?fuseaction=faq_listamp;ProdID=1amp;archive=1
http://&rouplo&ic.com:80/content/index.cfm?ID=103
http://&rouplo&ic.com:80/Knowled&e/index.cfm?fuseaction=viewamp;amp
http://&rouplo&ic.com:80/knowled&e/index.cfm?fuseaction=viewamp;docID=10
http://&rouplo&ic.com:80/content/index.cfm?ID=123
http://&rouplo&ic.com:80/Knowled&e/index.cfm?fuseaction=viewamp;docID=111
http://&rouplo&ic.com:80/news-events/index.cfm?fa=viewNewsamp;ID=390
http://&rouplo&ic.com:80/public/quickpoll/index.cfm?fuseaction=quickPollResultsamp;QuestionID=8
http://&rouplo&ic.com:80/content/index.cfm?ID=123amp;foo=bar
http://&rouplo&ic.com:80/store/index.cfm?cfid=11812682amp;cftoken=26157811amp;fa=conre
http://&rouplo&ic.com:80/store/index.cfm?fa=PrtSltamp;id=532amp;prTpID=5amp;
http://&rouplo&ic.com:80/store/index.cfm?    upTp=2amp;fa=up&radeamp;UpNewType=2amp;prTpID=5amp;amp;ptype=FS
http://&rouplo&ic.com:80/news-events/index.cfm?fa=viewReleaseamp;ID=21amp;prod=2
http://&rouplo&ic.com:80/content/index.cfm?fuseaction=faq_listamp;ProdID=1amp;archive=1
http://&rouplo&ic.com:80/content/index.cfm?ID=103
http://&rouplo&ic.com:80/Knowled&e/index.cfm?fuseaction=viewamp;amp
http://&rouplo&ic.com:80/knowled&e/index.cfm?fuseaction=viewamp;docID=10
http://&rouplo&ic.com:80/content/index.cfm?ID=123

$: ./tst urls
http://&rouplo&ic.com:80/store/index.cfm?upTp=2amp;ptype=FSamp;prTpID=5amp;fa=up&radeamp;UpNewType=2
http://&rouplo&ic.com:80/store/index.cfm?prTpID=5amp;id=532amp;fa=PrtSlt
http://&rouplo&ic.com:80/store/index.cfm?fa=conreamp;cftoken=26157811amp;cfid=11812682
http://&rouplo&ic.com:80/public/quickpoll/index.cfm?fuseaction=quickPollResultsamp;QuestionID=8
http://&rouplo&ic.com:80/news-events/index.cfm?prod=2amp;fa=viewReleaseamp;ID=21
http://&rouplo&ic.com:80/news-events/index.cfm?fa=viewNewsamp;ID=390
http://&rouplo&ic.com:80/knowled&e/index.cfm?fuseaction=viewamp;docID=10
http://&rouplo&ic.com:80/content/index.cfm?fuseaction=faq_listamp;archive=1amp;ProdID=1
http://&rouplo&ic.com:80/content/index.cfm?foo=baramp;ID=123
http://&rouplo&ic.com:80/content/index.cfm?ID=103
http://&rouplo&ic.com:80/Knowled&e/index.cfm?fuseaction=viewamp;docID=111
http://&rouplo&ic.com:80/Knowled&e/index.cfm?fuseaction=viewamp;amp
  

Обратите внимание, что выходные данные отсортированы с учетом регистра ASCII, с удалением завершающих и повторяющихся / избыточных амперсандов.

Выполнение этого в perl с помощью внутренних операций чтения и сортировки также намного быстрее.

 real    0m0.170s
user    0m0.046s
sys     0m0.092s
  

старая версия

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

 lst=( $( sort -ru x ) ) # unique reverse sort once to eliminate simple dups

for (( ndx1=0; ndx1<${#lst[@]}-1; ndx1   ))       # walk thru once in outer loop
do [[ -n "${lst[ndx1]}" ]] || continue            # i&nore removed
   for (( ndx2=ndx1 1; ndx2<${#lst[@]}; ndx2   )) # inner skips prev, no redux
   do case "${lst[ndx1]}" in                      # case statement strin& match
      "${lst[ndx2]}"*) unset lst[ndx2] ;;         # remove shorter versions
                    *) continue 2      ;;         # no match, skip ahead
      esac
   done
done

printf "%sn" "${lst[@]}"                         # print out what's left
  

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

Внешний цикл обходит массив один раз; он не беспокоится о последней записи, потому что внутренний цикл обработает это. Внутренний цикл начинается с записи после текущей из внешнего цикла — нет причин повторно проверять предыдущие, поскольку они отсортированы.

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

case Инструкция проверяет каждую запись после текущей из внешнего цикла. Если внутренний ключ содержится в текущей записи ключа внешнего цикла, более короткая версия удаляется из массива с помощью unset , и цикл переходит к следующей записи, чтобы проверить это.

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

Это движущееся окно соответствующих записей должно выполнять минимальную работу впустую.

Комментарии:

1. Возможна проблема с чувствительностью к регистру.

2. Я использую вашу программу со списком URL в качестве параметра и получаю те же результаты, я имею в виду, что ни одна строка не удалена = (

3. Это предполагает соответствие регистра и порядка или всех аргументов. Я упускаю что-то важное?

4. Если ваш порядок аргументов меняется, это становится экспоненциально более сложной проблемой.

5. Привет. Аргумент представляет собой список URL-адресов, это может быть любой список URL-адресов, и он должен удалять все строки, содержащие избыточные аргументы, поскольку они есть в других строках с такими же, или одинаковыми и более,.

Ответ №2:

Я вижу следующий алгоритм для этого (к сожалению, я не знаю, как его реализовать):

Сначала вы сортируете свой файл в алфавитном порядке.

Затем вы читаете свой файл построчно, и если строка является подстрокой следующей строки, ее не следует помещать в результирующий файл.

Ответ №3:

Наконец, похоже, я это сделал) для этого тестового файла:

 $ cat file2
test?foo
test?bar
test?foo
test2?foo
test2?baz
test2?fooamp;bar
test2?baz
test?fooamp;bar
test?baramp;foo
test2?baramp;foo
test3?bar
test3?fooamp;baramp;baz
test2?fooamp;baramp;baz
test?fooamp;baramp;baz
  

Скрипт

 #!/bin/bash
declare -A resorces
raw=( $(sort -u $1) )
for url in "${raw[@]}"; { resorces[${url//?*}] =" ${url//*?}"; }
for res in "${!resorces[@]}"; {
    list=( ${resorces[$res]} )
    for i in "${!list[@]}"; {
        par=${list[$i]}
        unset list[$i]
        [[ ${list[@]} =~ $par ]] || result =("$res?$par")
    }
}
printf '%sn' "${result[@]}"
  

Результат

 $ ./test2 file2
test2?baramp;foo
test2?fooamp;baramp;baz
test3?fooamp;baramp;baz
test?baramp;foo
test?fooamp;baramp;baz
  

И для этого тестового файла:

 $ cat file
http://&rouplo&ic.com:80/Knowled&e/index.cfm?fuseaction=viewamp;docID=111
http://&rouplo&ic.com:80/news-events/index.cfm?fa=viewNewsamp;ID=390
http://&rouplo&ic.com:80/public/quickpoll/index.cfm?fuseaction=quickPollResultsamp;QuestionID=8
http://&rouplo&ic.com:80/store/index.cfm?cfid=11812682amp;cftoken=26157811amp;fa=conre
http://&rouplo&ic.com:80/store/index.cfm?fa=PrtSltamp;id=532amp;prTpID=5amp;
http://&rouplo&ic.com:80/store/index.cfm?upTp=2amp;fa=up&radeamp;UpNewType=2amp;prTpID=5amp;amp;ptype=FS
http://&rouplo&ic.com:80/news-events/index.cfm?fa=viewReleaseamp;ID=21amp;prod=2
http://&rouplo&ic.com:80/content/index.cfm?fuseaction=faq_listamp;ProdID=1amp;archive=1
http://&rouplo&ic.com:80/content/index.cfm?ID=103
http://&rouplo&ic.com:80/Knowled&e/index.cfm?fuseaction=viewamp;amp
http://&rouplo&ic.com:80/knowled&e/index.cfm?fuseaction=viewamp;docID=10
http://&rouplo&ic.com:80/content/index.cfm?ID=123
http://&rouplo&ic.com:80/content/index.cfm?ID=123
http://&rouplo&ic.com:80/content/index.cfm?ID=123
http://&rouplo&ic.com:80/content/index.cfm?ID=123amp;foo=bar
http://&rouplo&ic.com:80/content/index.cfm?ID=123amp;foo=bar
  

Результат

 $ ./test2 file
http://&rouplo&ic.com:80/content/index.cfm?fuseaction=faq_listamp;ProdID=1amp;archive=1
http://&rouplo&ic.com:80/content/index.cfm?ID=103
http://&rouplo&ic.com:80/content/index.cfm?ID=123amp;foo=bar
http://&rouplo&ic.com:80/public/quickpoll/index.cfm?fuseaction=quickPollResultsamp;QuestionID=8
http://&rouplo&ic.com:80/Knowled&e/index.cfm?fuseaction=viewamp;amp
http://&rouplo&ic.com:80/Knowled&e/index.cfm?fuseaction=viewamp;docID=111
http://&rouplo&ic.com:80/store/index.cfm?cfid=11812682amp;cftoken=26157811amp;fa=conre
http://&rouplo&ic.com:80/store/index.cfm?fa=PrtSltamp;id=532amp;prTpID=5amp;
http://&rouplo&ic.com:80/store/index.cfm?upTp=2amp;fa=up&radeamp;UpNewType=2amp;prTpID=5amp;amp;ptype=FS
http://&rouplo&ic.com:80/knowled&e/index.cfm?fuseaction=viewamp;docID=10
http://&rouplo&ic.com:80/news-events/index.cfm?fa=viewNewsamp;ID=390
http://&rouplo&ic.com:80/news-events/index.cfm?fa=viewReleaseamp;ID=21amp;prod=2
  

Комментарии:

1. Устраняет дублирующие элементы, но не удаляет меньшие подмножества parms.

2. добавьте http://&rouplo&ic.com:80/content/index.cfm?ID=103amp;foo=bar в свой набор данных, он все еще сохраняется http://&rouplo&ic.com:80/content/index.cfm?ID=103 .

3. Я протестировал это, и, похоже, это не удаляет ни одной строки: snipboard.io/lbHJQS.jp&

4. В вашем файле изменяется порядок аргументов. Я не рассматривал вопрос о переупорядочении. Мы можем , но это добавляет больше логики, и я не видел никаких обращений или переупорядочивания в списке примеров (я пропустил это?)

5. Да, но я считаю это другим набором опций