Bash, unire variabili in un unica riga.

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
Scrivi risposta
Avatar utente
Metallkros
Prode Principiante
Messaggi: 21
Iscrizione: venerdì 10 luglio 2020, 10:52
Desktop: ubuntu
Distribuzione: Ubuntu 18.04.4 LTS

Bash, unire variabili in un unica riga.

Messaggio da Metallkros »

Buonasera, sto cercando di creare un file csv, e la cosa più semplice che mi è venuta in mente è quella di unire tutte le informazioni su un'unica riga, usando come separatore la "," .

In pratica ho un txt del genere:

Codice: Seleziona tutto

Nome: xxxxxxxxxxxx
Cognome: xxxxxxxxxxxx
città: xxxxxxxxxxxx
via: xxxxxxxxxxxx
regione: xxxxxxxxxxxx
stato: xxxxxxxxxxxx
fusorio: xxxxxxxxxxxx
cellulare: xxxxxxxxxxxx

Nome: yyyyyyyyyyy
Cognome: yyyyyyyyyyy
città:yyyyyyyyyyy
via:yyyyyyyyyyy
regione:yyyyyyyyyyy
stato:yyyyyyyyyyy
fusorio:yyyyyyyyyyy
cellulare:yyyyyyyyyyy

ora ci sono altri gruppi di variabili con dati diversi, e vorrei appunto metterli tutti in una riga, ora ho provato con questo script:

Codice: Seleziona tutto

for F in ok02.txt 
do
{
        read SSID
        read MAC
        read Manuf
        read Type
        read Channel
        read Encryption
        read Last
        read GPS
        echo "$SSID:" "$MAC:" "$Manuf" "$Type" "$Channel" "$Encryption" "$Last" $GPS" >> ok04.tmp
} < $F
done
e funziona, ovvero mi torna:

Codice: Seleziona tutto

Nome: xxxxxxxxxxxx,Cognome: xxxxxxxxxxxx,città: xxxxxxxxxxxx, via: xxxxxxxxxxxx,regione: xxxxxxxxxxxx,stato: xxxxxxxxxxxx,fusorio: xxxxxxxxxxxx ...
il problema è che lo fa solo per le prime otto variabili, poi si ferma e non legge le altre.

conosco già il numero totale delle righe del file (cat ok02.txt| wc -l) e di ognuna delle variabili.
ho anche provato ad impostare la condizione iniziale in questo modo(anche se dubito che questa sia la sintassi corretta):

X=$(cat ok02.txt | wc -l)
for [[ F in ok02.txt && y=0;y<=X;y++ ]]

ma niente..
Avatar utente
UbuNuovo
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 4444
Iscrizione: sabato 12 dicembre 2009, 20:58
Desktop: Mate
Distribuzione: Ubuntu Mate 22.04.1 LTS
Sesso: Maschile
Contatti:

Re: Bash, unire variabili in un unica riga.

Messaggio da UbuNuovo »

Ho provato al volo da terminale:

Codice: Seleziona tutto

 8-) cat dati.txt
Nome: xxxxxxxxxxxx
Cognome: xxxxxxxxxxxx
città: xxxxxxxxxxxx
via: xxxxxxxxxxxx
regione: xxxxxxxxxxxx
stato: xxxxxxxxxxxx
fusorio: xxxxxxxxxxxx
cellulare: xxxxxxxxxxxx

Nome: yyyyyyyyyyy
Cognome: yyyyyyyyyyy
città:yyyyyyyyyyy
via:yyyyyyyyyyy
regione:yyyyyyyyyyy
stato:yyyyyyyyyyy
fusorio:yyyyyyyyyyy
cellulare:yyyyyyyyyyy

 8-)  while read l;do [ -z "$l" ] && echo ';' || echo -n "$l,";done < dati.txt
Nome: xxxxxxxxxxxx,Cognome: xxxxxxxxxxxx,città: xxxxxxxxxxxx,via: xxxxxxxxxxxx,regione: xxxxxxxxxxxx,stato: xxxxxxxxxxxx,fusorio: xxxxxxxxxxxx,cellulare: xxxxxxxxxxxx,;
Nome: yyyyyyyyyyy,Cognome: yyyyyyyyyyy,città:yyyyyyyyyyy,via:yyyyyyyyyyy,regione:yyyyyyyyyyy,stato:yyyyyyyyyyy,fusorio:yyyyyyyyyyy,cellulare:yyyyyyyyyyy,;
 8-) 
Naturalmente per salvare su file, puoi fare

Codice: Seleziona tutto

while read l;do [ -z "$l" ] && echo ';' || echo -n "$l,";done < dati.txt > dati.csv
P.s.: il punto e virgola finale non è obbligatorio:

Codice: Seleziona tutto

while read l;do [ -z "$l" ] && echo '' || echo -n "$l,";done < dati.txt > dati.csv
Salva l'Ucraina! 🇺🇦
Avatar utente
Metallkros
Prode Principiante
Messaggi: 21
Iscrizione: venerdì 10 luglio 2020, 10:52
Desktop: ubuntu
Distribuzione: Ubuntu 18.04.4 LTS

Re: Bash, unire variabili in un unica riga.

Messaggio da Metallkros »

Ululì Ululà è già la seconda volta che salvi le mie natiche :D , questa sera tornato da lavoro provo e ti faccio sapere
Avatar utente
vaeVictis
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 4703
Iscrizione: venerdì 27 luglio 2012, 17:58
Desktop: Gnome
Distribuzione: Ubuntu 20.04 64bit

Re: Bash, unire variabili in un unica riga.

Messaggio da vaeVictis »

Credo si possa usare awk e semplificare la procedura (oltre ad avere, credo, migliori performance* su file grandi):

Codice: Seleziona tutto

cat foo.txt 
Nome: xxxxxxxxxxxx
Cognome: xxxxxxxxxxxx
città: xxxxxxxxxxxx
via: xxxxxxxxxxxx
regione: xxxxxxxxxxxx
stato: xxxxxxxxxxxx
fusorio: xxxxxxxxxxxx
cellulare: xxxxxxxxxxxx

Nome: yyyyyyyyyyy
Cognome: yyyyyyyyyyy
città:yyyyyyyyyyy
via:yyyyyyyyyyy
regione:yyyyyyyyyyy
stato:yyyyyyyyyyy
fusorio:yyyyyyyyyyy
cellulare:yyyyyyyyyyy

Nome: zzzzzzzzzzzzz
Cognome: zzzzzzzzzzz
città:zzzzzzzzzzz
via: zzzzzzzzzzz
regione: zzzzzzzzzz
stato: zzzzzzzzzzzz
fusorio: zzzzzzzzzzzz
cellulare: zzzzzzzzzzzzzzz

Codice: Seleziona tutto

awk 'NR%9{printf "%s,",$0;next}{print;}' foo.txt 
Nome: xxxxxxxxxxxx,Cognome: xxxxxxxxxxxx,città: xxxxxxxxxxxx,via: xxxxxxxxxxxx,regione: xxxxxxxxxxxx,stato: xxxxxxxxxxxx,fusorio: xxxxxxxxxxxx,cellulare: xxxxxxxxxxxx,
Nome: yyyyyyyyyyy,Cognome: yyyyyyyyyyy,città:yyyyyyyyyyy,via:yyyyyyyyyyy,regione:yyyyyyyyyyy,stato:yyyyyyyyyyy,fusorio:yyyyyyyyyyy,cellulare:yyyyyyyyyyy,
Nome: zzzzzzzzzzzzz,Cognome: zzzzzzzzzzz,città:zzzzzzzzzzz,via: zzzzzzzzzzz,regione: zzzzzzzzzz,stato: zzzzzzzzzzzz,fusorio: zzzzzzzzzzzz,cellulare: zzzzzzzzzzzzzzz,
p.s.: ho editato il messaggio perché con il comando precedente non metteva le virgole.


*) si può dire "performance" su questo forum? :D
Pirates arrrrrrrrrrr awesome!!!
«I fear not the man who has practiced 10000 kicks once,
but I fear the man who has practiced one kick 10000 times.»
korda
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1720
Iscrizione: giovedì 24 dicembre 2020, 15:58

Re: Bash, unire variabili in un unica riga.

Messaggio da korda »

Arrivo in ritardo, vedo solo ora...

Non conosco molto il bash script, forse meno delle basi necessarie. In ogni caso, su questo genere di problematiche di parsing di testo in genere, ho una nutrita collezione di script in Perl che ho fatto nel corso degli anni.

Se vi servisse sono a disposizione... :ciao:
Io non sono Bagheera né Akela, io non frequento la Rupe.
Io sono Kaa: faccio ballare le scimmie alle Tane Fredde.
Avatar utente
vaeVictis
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 4703
Iscrizione: venerdì 27 luglio 2012, 17:58
Desktop: Gnome
Distribuzione: Ubuntu 20.04 64bit

Re: Bash, unire variabili in un unica riga.

Messaggio da vaeVictis »

Mi riaffaccio perché è più o meno tutto il giorno che questa discussione mi frulla per la testa.
Ho alcune considerazioni.

1) la virgola finale è brutta. Non ci sono ulteriori campi e quindi dovrebbe essere rimossa.
2) generalizzando, potrebbe darsi che nel file ci siano più di una singola riga vuota che separi i singoli gruppi di otto informazioni
3) sempre generalizzando, potrebbe capitare di trovare delle righe vuote tra le righe che corrispondono a un gruppo di otto informazioni
4) potrebbero esserci delle righe vuote alla fine del file, o anche all'inizio del file.

Fatte queste generalizzazioni, si ottiene un file "generico" di questo tipo:

Codice: Seleziona tutto



Nome: xxxxxxxxxxxx
Cognome: xxxxxxxxxxxx
città: xxxxxxxxxxxx

via: xxxxxxxxxxxx
regione: xxxxxxxxxxxx

stato: xxxxxxxxxxxx
fusorio: xxxxxxxxxxxx
cellulare: xxxxxxxxxxxx



Nome: yyyyyyyyyyy


Cognome: yyyyyyyyyyy
città:yyyyyyyyyyy
via:yyyyyyyyyyy

regione:yyyyyyyyyyy
stato:yyyyyyyyyyy
fusorio:yyyyyyyyyyy
cellulare:yyyyyyyyyyy

Nome: zzzzzzzzzzzzz
Cognome: zzzzzzzzzzz
città:zzzzzzzzzzz
via: zzzzzzzzzzz
regione: zzzzzzzzzz
stato: zzzzzzzzzzzz
fusorio: zzzzzzzzzzzz
cellulare: zzzzzzzzzzzzzzz






Il comando che gestisce tutte queste eccezioni è il seguente:

Codice: Seleziona tutto

awk 'BEGIN {i=1} NF { if  ( i<=7 ) { printf("%s,", $0); i++ } else { print; i = 1 } }' foo.txt 
Nome: xxxxxxxxxxxx,Cognome: xxxxxxxxxxxx,città: xxxxxxxxxxxx,via: xxxxxxxxxxxx,regione: xxxxxxxxxxxx,stato: xxxxxxxxxxxx,fusorio: xxxxxxxxxxxx,cellulare: xxxxxxxxxxxx
Nome: yyyyyyyyyyy,Cognome: yyyyyyyyyyy,città:yyyyyyyyyyy,via:yyyyyyyyyyy,regione:yyyyyyyyyyy,stato:yyyyyyyyyyy,fusorio:yyyyyyyyyyy,cellulare:yyyyyyyyyyy
Nome: zzzzzzzzzzzzz,Cognome: zzzzzzzzzzz,città:zzzzzzzzzzz,via: zzzzzzzzzzz,regione: zzzzzzzzzz,stato: zzzzzzzzzzzz,fusorio: zzzzzzzzzzzz,cellulare: zzzzzzzzzzzzzzz
Ora posso andare a dormire tranquillo. :ciao:
Pirates arrrrrrrrrrr awesome!!!
«I fear not the man who has practiced 10000 kicks once,
but I fear the man who has practiced one kick 10000 times.»
Avatar utente
UbuNuovo
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 4444
Iscrizione: sabato 12 dicembre 2009, 20:58
Desktop: Mate
Distribuzione: Ubuntu Mate 22.04.1 LTS
Sesso: Maschile
Contatti:

Re: Bash, unire variabili in un unica riga.

Messaggio da UbuNuovo »

@Vae: I due tipi di codice hanno pro e contro:
il codice con il ciclo while si basa sulla riga vuota tra record, indipendentemente dal numero di campi.

Per eliminare l'ultima virgola basterebbe aggiungere sed 's/,$//'.

Codice: Seleziona tutto

while read l;do [ -z "$l" ] && echo '' || echo -n "$l,";done < dati.txt | sed 's/,$//' > dati.csv
Il codice awk si basa sul numero di campi e, l'ultimo codice, indipendentemente dalla disposizione delle righe vuote.
Credo anch'io che il codice awk abbia prestazioni migliori, rispetto al ciclo while; quest'ultimo è più adatto nei casi in cui si debbano fare altre elaborazioni, è più facile metterci le mani, visto che per sua natura elabora una riga di dati per volta, cosa comunque fattibile anche con awk.
Salva l'Ucraina! 🇺🇦
Avatar utente
Metallkros
Prode Principiante
Messaggi: 21
Iscrizione: venerdì 10 luglio 2020, 10:52
Desktop: ubuntu
Distribuzione: Ubuntu 18.04.4 LTS

Re: Bash, unire variabili in un unica riga.

Messaggio da Metallkros »

Ciao a tutti e grazie per le risposte, @vaeVictis allora con awk ho alcune difficoltà, nel senso che in generale non ci capisco una mazza(avevo già provato a fare qualcosa con awk prima di aprire il topic) però funziona alla grande cercherò il manuale e lo studierò un pò per capire meglio il codice che mi hai fornito :D , @UbuNuovo ho provato con il tuo codice, ma quando apro il csv tutto il contenuto viene scritto su un'unica riga, ho provato anche a cambiarlo così:

Codice: Seleziona tutto

while read l;do [ -z "$l" ] && echo -e "\n" || echo -n "$l,";done < dati.txt > dati.csv
ma nulla.
korda
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1720
Iscrizione: giovedì 24 dicembre 2020, 15:58

Re: Bash, unire variabili in un unica riga.

Messaggio da korda »

Scusate se rompo le scatole, ma mi sembra ci sia la tendenza a ottimizzare il codice in poche righe quando non sussistano problemi di performance (a meno che il tuo file di testo non abbia GigaByte di roba). Posso umilmente suggerire un approccio più tradizionale?

Tipo prendi un qualsiasi linguaggio di scripting, non necessariamente bash script con awk o sed, e procedi in modo lineare:

1. Ti crei un hash table annidata con i campi che ti interessano.
2. Apri il file di testo
3. Cicli sul file di testo riga per riga
4. Parsi ogni riga con una regex
5. Dal match della espressione regolare fai uno switch of per scegliere di quale campo si tratta
6. Salvi il contenuto della riga parsata in una nuova entry dalla hashtable nello specifico campo
7. Continui da 3. fino a EOF
8. Cicli sull'hashtable che hai riempito nel ciclo precedente
9. Ad ogni entry fai una join di tutti i campi usando ; come separatore
10. Della stringa creata in 9. reindirizzi lo stdout su un file di testo csv

Ripeto, se non hai file di dimensioni di GB non è necessario condensare tutto questo in una o due righe di codice. In più il codice potrebbe tornarti leggibile di nuovo tra qualche anno se, nel frattempo, non usi più tanto spesso lo scripting.

Questa è solo un mio umile parere. Poi fate vobis
Io non sono Bagheera né Akela, io non frequento la Rupe.
Io sono Kaa: faccio ballare le scimmie alle Tane Fredde.
Avatar utente
UbuNuovo
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 4444
Iscrizione: sabato 12 dicembre 2009, 20:58
Desktop: Mate
Distribuzione: Ubuntu Mate 22.04.1 LTS
Sesso: Maschile
Contatti:

Re: Bash, unire variabili in un unica riga.

Messaggio da UbuNuovo »

Metallkros ha scritto:
sabato 29 maggio 2021, 15:23
Ciao a tutti e grazie per le risposte, @vaeVictis allora con awk ho alcune difficoltà, nel senso che in generale non ci capisco una mazza(avevo già provato a fare qualcosa con awk prima di aprire il topic) però funziona alla grande cercherò il manuale e lo studierò un pò per capire meglio il codice che mi hai fornito :D , @UbuNuovo ho provato con il tuo codice, ma quando apro il csv tutto il contenuto viene scritto su un'unica riga, ho provato anche a cambiarlo così:

Codice: Seleziona tutto

while read l;do [ -z "$l" ] && echo -e "\n" || echo -n "$l,";done < dati.txt > dati.csv
ma nulla.
Se metti /n oltre ad andare a capo dovrebbe lasciare una riga vuota, echo da solo manda a capo.
Se non funge vuol dire che la riga vuota non è realmente vuota, potrebbero esserci degli spazi, controlla.

In quel caso dovrebbe funzionare questo:

Codice: Seleziona tutto

while read l;do [[ $l =~ ^\s*$ ]] && echo '' || echo -n "$l,";done < dati.txt | sed 's/,$//' > dati.csv
@korda: sono d'accordo, ho scritto tutto su una riga, perché non ho fatto uno script ma provato solo nel terminale.
Salva l'Ucraina! 🇺🇦
korda
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1720
Iscrizione: giovedì 24 dicembre 2020, 15:58

Re: Bash, unire variabili in un unica riga.

Messaggio da korda »

UbuNuovo ha scritto:
sabato 29 maggio 2021, 16:20
@korda: sono d'accordo, ho scritto tutto su una riga, perché non ho fatto uno script ma provato solo nel terminale.
Perdonami lo sfogo @UbuNuovo. È solo dettato dalla frustrazione di riprendere più e più volte bashscript scritti da altri e doverli "ritradurre" in modo comprensibile perché puntualmente si sollevava un'eccezione criptica ed erano inutilizzabili (aka un errore da trovare su una riga lunga un kilometro)

Edit: usare un hashtable come variabile di deposito intermedia non è necessario. È solo una questione di comodità, nel senso che a posteriori te la puoi manipolare come meglio ti aggrada per costruirti un csv ad hoc.

Chiuso l'OT
Ultima modifica di korda il sabato 29 maggio 2021, 17:01, modificato 1 volta in totale.
Io non sono Bagheera né Akela, io non frequento la Rupe.
Io sono Kaa: faccio ballare le scimmie alle Tane Fredde.
Avatar utente
vaeVictis
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 4703
Iscrizione: venerdì 27 luglio 2012, 17:58
Desktop: Gnome
Distribuzione: Ubuntu 20.04 64bit

Re: Bash, unire variabili in un unica riga.

Messaggio da vaeVictis »

@Metallkros
Ciao a tutti e grazie per le risposte, @vaeVictis allora con awk ho alcune difficoltà, nel senso che in generale non ci capisco una mazza(avevo già provato a fare qualcosa con awk prima di aprire il topic) però funziona alla grande cercherò il manuale e lo studierò un pò per capire meglio il codice che mi hai fornito
Allora te lo spiego, è abbastanza semplice. Il comando awk è:

Codice: Seleziona tutto

awk 'BEGIN {i=1} NF { if  ( i<=7 ) { printf("%s,", $0); i++ } else { print; i = 1 } }'
in cui:

Codice: Seleziona tutto

BEGIN {i=1}
indica a awk di impostare la variabile i al valore 1 quando lo script viene avviato.

Dopodiché awk legge una riga per volta.

Codice: Seleziona tutto

NF
è una variabile interna di awk che indica il numero di campi (Number of Fields) della riga. Usata in quel modo indica ad awk di eseguire il codice successivo solo quando NF è "vera", ossia differente da zero, ossia quando sulla riga c'è scritto qualcosa.

Quindi ogni volta che awk incontra una riga non vuota fa questo:

Codice: Seleziona tutto

{ if  ( i<=7 ) { printf("%s,", $0); i++ } else { print; i = 1 } }
che vuol dire:
1)

Codice: Seleziona tutto

 if  ( i<=7 ) { printf("%s,", $0); i++ }
se i è minore o uguale a 7, stampa la riga con una virgola finale, senza andare a capo, e incrementa di 1 il valore di i.
2)

Codice: Seleziona tutto

 else { print; i = 1 }
altrimenti stampa la riga andando a capo e reimposta i (che ora vale 8 ) ad 1.

@korda
Non sono d'accordo con nessuna parola del tuo ultimo messaggio. Avevo scritto una risposta, ma l'ho cancellata preferendo rimanere in topic e rispondere all'OP.
Pirates arrrrrrrrrrr awesome!!!
«I fear not the man who has practiced 10000 kicks once,
but I fear the man who has practiced one kick 10000 times.»
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: DjDiabolik, Lucio C, TommyB1992 e 18 ospiti