Newsgroup: it.comp.os.linux.iniziare
Titolo: Esercizio complicato.

Sto seguendo un corso di linux online, mi è stato assegnato un esercizio 
da completare con la programmazione della shell, bash.
Non so proprio come fare, mi date una mano:
 
Esercizio schell bash linux:
 
dato un file html in input indivuare:
 
1) tutte le occorrenze univoche degli indirizzi http e https presenti
2) quante occorenze esistono per ciascuna occorenza univoca
3) salvare su un file occorrenze.dat sulla scrivania dell'utente 
corrente o, sempre in input, su una locazione data. In caso di errore 
della locazione indicata salvare sulla scrivania dell'utente corrente.
 
Grazie anticipatamente.


L'occorrenza univoca e' interessante.
 
Se per univoca s'intende il sito in se'
senza considerare se https o no, questa sarebbe
una occorrenza sola:
 
https://www.ilmiocane.org/
 
https://ilmiocane.org/
 
https://www.ilmiocane.org
 
https://ilmiocane.org
 
http://www.ilmiocane.org/
 
http://ilmiocane.org/
 
http://www.ilmiocane.org
 
http://ilmiocane.org
 
 
Ma magari alcuni siti non supportano https o rispondo
solo ad uno dei due URL con o senza www.
 
Dai scherzo, dovrei googlare anche io, non ho tempo,
sara' l'eguaglianza dell'indirizzo, anche se la barra finale... :-D


Non conosco bash ma dal punto di vista concettuale, facendo riferimento 
al LutherBlisset:
On 17/11/20 08:52, LutherBlissett wrote:
 > On 17/11/2020 08:27, Maet wrote:

 > L'occorrenza univoca e' interessante.
 >
 > Se per univoca s'intende il sito in se'
 > senza considerare se https o no, questa sarebbe
 > una occorrenza sola:
 >
 > 
https://www.ilmiocane.org/
 
 > 
https://ilmiocane.org/
 
 > 
https://www.ilmiocane.org
 
 > 
https://ilmiocane.org
 
 > 
http://www.ilmiocane.org/
 
 > 
http://ilmiocane.org/
 
 > 
http://www.ilmiocane.org
 
 > 
http://ilmiocane.org
 
 >
 > Ma magari alcuni siti non supportano https o rispondo
 > solo ad uno dei due URL con o senza www.
 >
 > Dai scherzo, dovrei googlare anche io, non ho tempo,
 > sara' l'eguaglianza dell'indirizzo, anche se la barra finale... :-D
 
puoi iniziare a vedere cosa c'è tra http(s)://<nome sito>(/) e poi 
cercare il nome del sito trovando la stringa "
ilmiocane.org
" per le 
altre come controllo, tutte le altre combinazioni sono sotto insiemi dei 
precedenti casi quindi ignorarle.
Creare le variabili e un array.
occorrenze_totali
variabile posizione scrivania
variabile posizione scelta
con un while eof leggi il file.
Direi: matrice "nome_univoco" "occorrenze" per i nomi univoci che trovi 
e quante ne trovi, contatore dei nomi trovati.
Gestione dell'errore: alla fine del conteggio
if posizione_corretta then
	occorrenze_totali
	for 1 to occorrenze_totali then
		variabile posizione scelta "nome_univoco" "occorrenze" > occorrenze.dat
else posizione_non_corretta then
	occorrenze_totali
	for 1 to occorrenze_totali then
		variabile posizione scrivania utente "nome_univoco" "occorrenze" > 
occorrenze.dat
end
Dal punto di vista del diagramma di flusso dovrebbe essere così.


Come pagina html di test ho provato a scaricare questa:
wget -O test.html '
https://stackoverflow.com/questions/41001475/extract-part-of-the-code-and-parse-html-in-bash
'
 
 
Ok, questo comando qui sotto dovrebbe trovare tutti gli indirizzi
http(s), li mette uno per riga e poi calcola il numero di occorrenze
stampando nella forma "numero	url".
 
sed -n 's/^.*http\([^"]*\)".*$/http\1/gp' test.html|uniq -c > occorrenze.dat
 
Il resto dello script è una roba da poco:
controllare se esiste una variabile in input, altrimenti settarla ad un
valore di default, che sarebbe la scrivania dell'utente ~/Desktop.
Questo fallo per esercizio...
 
Per esercizio in risposta potresti spiegare come funziona il mio
comando sopra. Così ti vai a vedere la REGEX di sed, l'opzione -n
in combinata col comando 'p' e l'aggiunta del 'g'.
In più ti dai un occhio al man di uniq, ma quello è facile.
 
Quando hai capito spiega in risposta al gruppo, credo che ti serva
a qualcosa per imparare.

 sed -n 's/^.*http\([^"]*\)".*$/http\1/gp' test.html|uniq -c > occorrenze.dat
 
Scusa solo per curiosita', ma bada che uniq, a differenza di
sort -u, taglia le righe uguali solo se consecutive ciao
(forse conviene "... | sort | uniq -c" per contarle ed invece
"... | sort -u" per togliere tutti i doppioni)
 
(a Maet hai gia' risposto tu, anche se non capisco i corsi
che hanno bisogno di insegnanti di sostegno (tu) esterni)
 
-- 
Yoda
 


Infatti c'è il trucco... Anzi più di uno, oltre a quello che
hai trovato tu!
 
Si consideri questo altro input di esempio per vedere meglio
cosa accade:
----------------
$ cat input.test
prima riga
seconda riga "
http://example.secondariga.invalid
" e c'è anche "
https://exampledue.secondariga.invalid
" e il resto via...
terza riga con solo "
https://example.terzariga.invalid
"
qua niente link
qua neanche
sesta riga "
http://pippo.invalid
" con altro link "
https://example.terzariga.invalid
"
settima riga "
http://pippo.invalid
"
-----------------------------------

Addi' 17 nov 2020 13:48:40, Joe scrive:

E allora figuriamoci! bisogna isolarli tutti.. be' un modo veloce
per farlo e' questo: "grep -o [[:graph:]]*http[[:graph:]]*" ciao
 
Con questo tuo input.test qui su, senza togliere e/o contare i
doppi, da':
-------------------
"
http://example.secondariga.invalid
"
"
https://exampledue.secondariga.invalid
"
"
https://example.terzariga.invalid
"
"
http://pippo.invalid
"
"
https://example.terzariga.invalid
"
"
http://pippo.invalid
"
----------------
 
-- 
Yoda
 


L'ho provato con un file reale e non va molto bene.
Meglio quello di Joe... ;)


Funziona ma non riesco ad eliminare i doppioni... inoltre mi rimangono 
sempre da eliminare http:// e la parte successiva a /.
Ciao

 ----------------
 
Ottimo, "grep -o" mostra solo (only) la regex intercettata.
Buona idea, ma due problemi:
 
1- restano le virgolette nell'output
2- il mio esempio era troppo semplice, se guardi un html gli
   url non sono isolati da spazi come nel mio esempio.
 
Ecco un input.test un po' più vicino alla realtà dell'html:
----------------
$ cat input.test
----------------
prima riga
seconda riga tagrognoso="
http://example.secondariga.invalid
" e c'è anche
"
https://exampledue.secondariga.invalid
" e il resto via...
terza riga con solo url="
https://example.terzariga.invalid
"
qua niente link
qua neanche
sesta riga "
http://pippo.invalid
" con altro link
"
https://example.terzariga.invalid
" blabla
settima riga "
http://pippo.invalid
"
-----------------------------------
 
Se applichi il tuo grep non funziona più così.
C'è un modo abbastanza simile al tuo per farlo con grep
attivando il formato Perl regex, ma volendo restare alla
rude didatica, si può ragionare in due tempi:
 
- prima faccio in modo che tutti gli indirizzi, cioè
  tutto ciò che inizia per http venga piazzato ad inizio
  riga.
 
- poi per ogni riga che inizia con http butto via ciò che
  segue le virgolette
 
- infine do tutto in pasto a "sort | uniq -c"
 
Tradotto in pratica messo su più righe:
 
sed -n 's/http/\nhttp/gp' input.test \
    | sed -n '/^http/s/".*$//p' \
    | sort \
    | uniq -c
 
 
 
La versione più elegante trovata su stackoverflow o simili:
----------------------------------------------------------
$ grep -oP '(?<=\")http.*?(?=\")' input.test|sort|uniq -c
	1 
http://example.secondariga.invalid
 
	2 
http://pippo.invalid
 
	2 
https://example.terzariga.invalid
 
	1 
https://exampledue.secondariga.invalid
 
------------------------------------------------
 
In ogni caso l'output è uguale alla soluzione più rozza.


Per i doppiono dovresti aver risolto immagino, leggendo il resto della
discussione, in particolare la mia ultima risposta.
 
Riguardo al protocollo http ecc, perché mai devi eliminarlo?
Fanno parte del link dopotutto. Sì l'indirizzo sta in piedi
anche senza, ma se si conosce che è criptato o in chiaro mi
pare un'informazione in più, potenzioalmente utile...
Poi dipende sempre dalla destinazione d'uso, ma anche in vista
di un riutilizzo dei link in un altro pezzo dello script io
li lascerei. Certo dipende anche dal testo del tuo esercizio,
da quanto chiedi deduco che  non ci hai mostrato per intero cosa
chiede.
Anche la parte successiva allo slash dell'indirizzo "/", se la
butti via, poi dovesse servire non potrai più raggiungerlo.
 
Comuque prndi un pezzo di una pagina html vera, scaricata dal web,
seleziona tot righe in modo che contengano 5 o 6 links. Poi estrai
a mano i links e scrivili uno per riga in modo univoco con di fianco
il numero di occorrenze di ciascuno.
In questo modo capiamo di preciso in che formato vuoi l'output.
 
Però l'esercizio devi farlo tu se stai frequentando un corso,
altrimenti la mia pappa pronta o quella degli altri che ti danno
la soluzione non ti serve a nulla.
Ecco perché col mio primo codice hai qualche problema, perché
sta a te correggerlo. E se vuoi spiegarci come hai ragionato:
così s'impara, non scopiazzndo, ma ragionando.

 In ogni caso l'output è uguale alla soluzione più rozza.
 
Mah.. io ci capisco troppo poco di reti, quel sed che t'ho dato qui
su taglia via ogni carattere che non sia ne' alfanumerico ne' di
controllo ne' spazi o tab. Non so se i caratteri della classe
"[:punct:]" possano o no far parte di un URLo ciao
 
 
Postilla. Per chiarezza la riga completa per gli URLi puliti e':
 
grep -o http[[:graph:]]* input.test | sed 's/[[:punct:]]*$//' \
| sort | uniq -c
 
otterresti:
-----------------
      1 
http://example.secondariga.invalid
 
      2 
http://pippo.invalid
 
      1 
https://exampledue.secondariga.invalid
 
      2 
https://example.terzariga.invalid
 
--------------------
 
che mi sembra identico al perl, salvo l'ordine alfabetico ariciao
 
(sai che col solo awk, o col solo perl, scommetto che si fa
completo, senza grep sed sort uniq o altro? solo che awk e perl
son delle brutte bestie..)
 
-- 
Yoda
 

 son delle brutte bestie..)
 
Certamente...
Ma la filosofia unix di dare a ognuno il suo compito di solito
si è rivelata un punto di forza.
 
Comunque sì se conosci il perl con questi problemi sei avantaggiato,
awk non lo conosco bene, so che è molto più spinto di sed e in alcuni
casi, dove serve una soluzione che gira rapidamente, tipo se hai a che
fare con files grandi, sono due alternative da preferire agli utensili
più terra terra tipo grep o sed... a me era capitato che ad esempio
sed doveva fare due passate del file per lo scopo e questo rallentava
parecchio rispetto a corrispondente soluzione perl che avevo scopiazzato
in rete.
 
Poi a volerla dire tutta, si potrà fare anche in python a quel punto,
ci sono migliaia di moduli che rendono la cosa probabilmente semplice
da implementare.
Ma andiamo OT rispetto alla domanda iniziale, mi pare che dovesse usare
strumenti base della shell bash... Anche se alla fine neanche grep o
sed sono strumenti base volendo. Però insomma ci sono struemnti "più base
di altri", diciamo così.


Ho provato con una pagina web e funziona alla grande.
E' un "periodaccio", non riesco a fare questo benedetto esercizio, 
proprio a metterci mano, ma una mano mi è arrivata!
In pratica ci viene limitato il campo alla shell e a bash.
Trovare la stringa dopo // (non è detto che ci sia necessariamente /) 
servirebbe per prendere esattamente il nome del sito e poter fare i 
conteggi. In effetti conviene estrarre con il vostro script tutte le 
occorrenze e poi da quello fare un ulteriore passo, utilizzandolo come 
input allo script successivo. Ero partito con uno script unico ma 
ovviamente era un groviglio di errori. ;)
Grazie mille ad entrambi!

 ovviamente era un groviglio di errori. ;)
 
Un consiglio spassionato, che forse ti avevo già dato: quando si
pongono domande come la tua, si deve essere precisi su quale deve
essere il risultato finale. E per esserlo non c'è niente di meglio
che un esempio (exempla utiliora quam consilia...).
 
In questo caso, potevi prendere una pagina web a tua scelta.
Scaricarla con wget in locale.
Aprirla e vedere quali links contiene.
Poi manualmente li copi e incolli in un file di testo per poi riportarli
nel tuo mesaggio scrivendo:
 
- *se in input ho questa pagina*:
 
  *
http://link
 alla pagina di test da usare come input*
 
       così possiamo scaricarcelo anche noi e provare
       su qualcosa di concreto
 
- *voglio ottenere questo output come risultato:*
 
       e metti la lista dei siti così come vuoi che il
       tuo script la sputi fuori, precisamente e senza
       possibilità di interpretazioni non univoche.
 
 
Comunque ti ripeto, se serve solo il conteggio, l'http iniziale e
l'eventuale roba seguente lo slash puoi tranquillamente lasciarla,
non fa sballare i conti.
Se invece ti serve un output differente allora fai l'esempio, tanto
vedi come si usa wget o curl per scaricare la pagina di input...


Okay. Allego i file di esempio e input.test è copiato dal link 
www.libero.it
 
Ecco gli shorturl dei file inviati tramite wetransfer:
 
http://alturl.com/jc6mg
 
http://alturl.com/5o5rn
 
http://alturl.com/tb6s4
 
 
Ovviamente sul file di output ho messo dati a caso.

On 20/11/20 12:05, Joe wrote:

Ho chiesto al prof sul forum: possiamo utilizzare sia perl o in 
alternativa python, avevo interpretato male la traccia.
Qualche ulteriore suggerimento?

 Qualche ulteriore suggerimento?
 
Si, studiare il materiale che sicuramente
era dato relativamete a questo esercizio.
 
Probabilmente c'e` gia` la soluzione dentro.
 
Mi sembrerebbe strano, anche se succede,
che venga dato un esercizio senza che
prima si siano discussi i metodi da usare
per poi risolverlo.
 
bye,
 
-- 
 
piergiorgio