È possibile sostituire il valore di una cella in un file csv utilizzando grep,sed, o entrambi

0

Domanda

Ho scritto il seguente comando

#!/bin/bash
awk -v value=$newvalue -v row=$rownum -v col=1 'BEGIN{FS=OFS=","} NR==row {$col=value}1' "${file}".csv >> temp.csv && mv temp.csv "${file}".csv

Esempio di Input di file.csv

Header,1
Field1,Field2,Field3
1,ABC,4567
2,XYZ,7890

Assuiming $newvalue=3 ,$rownum=4 e col=1, quindi il codice di cui sopra andrà a sostituire:

Richiesta Di Uscita

Header,1
Field1,Field2,Field3
1,ABC,4567
3,XYZ,7890

Quindi, se io so di riga e di colonna, è possibile sostituire il valore con grep, sed?

Edit1: Campo3 avrà sempre un valore univoco per le loro rispettive righe. ( in caso di informazioni aiuta comunque)

bash csv git-bash linux
2021-11-24 06:52:47
3

Migliore risposta

1

Supponendo che il file CSV è semplice come ciò che si mostra (senza virgole nei campi tra virgolette), e il newvalue non contengono caratteri sed vorresti interpretare in un modo particolare (ad esempio commerciali, barre o backslash), il seguente dovrebbe funzionare solo con sed (testato con GNU sed):

sed -Ei "$rownum s/[^,]*/$newvalue/$col" file.csv

Demo:

$ cat file.csv
Header,1
Field1,Field2,Field3
1,ABC,4567
3,XYZ,7890
$ rownum=3
$ col=2
$ newvalue="NEW"
$ sed -Ei "$rownum s/[^,]*/$newvalue/$col" file.csv
$ cat file.csv
Header,1
Field1,Field2,Field3
1,NEW,4567
3,XYZ,7890

Spiegazioni: $rownum è usato come indirizzo (qui il numero di riga) dove applicare il comando riportato di seguito. s è la sed comando di sostituzione. [^,]* è l'espressione regolare per la ricerca e la sostituzione: il più a lungo possibile stringa che contiene una virgola. $newvalue è la stringa di sostituzione. $col è la presenza di sostituire.

Se newvalue può contenere e commerciali, barre o backslash dobbiamo sterilizzare prima:

sanitizednewvalue=$(sed -E 's/([/\&])/\\\1/g' <<< "$newvalue")
sed -Ei "$rownum s/[^,]*/$sanitizednewvalue/$col" file.csv

Demo:

$ newvalue='NEW&\/&NEW'
$ sanitizednewvalue=$(sed -E 's/([/\&])/\\\1/g' <<< "$newvalue")
$ echo "$sanitizednewvalue"
NEW\&\\\/\&NEW
$ sed -Ei "$rownum s/[^,]*/$sanitizednewvalue/$col" file.csv
$ cat file.csv
Header,1
Field1,Field2,Field3
1,NEW&\/&NEW,4567
3,XYZ,7890
2021-11-24 11:13:43

Questo non funziona. Solo alcuni indicatori, però: non ero a conoscenza prima di questa risposta di ` [^,]*` ma se sed è in grado di sostituire per una specifica cella, quindi perché siamo tra [^,]* . Ho fatto provare sed -Ei "$rownum s/$newvalue/$col" file.csv e ha gettato un errore, ma Vorrei sapere di più su questo. Qualsiasi risorsa a leggere su sarebbe utile pure.
Helium

Abbiamo bisogno di ` [ ^ ,]*`, perché è ciò che definisce ciò che un cellulare è. sed non è un CSV processore, è un qualsiasi elaboratore di testo. Quindi non ha alcuna conoscenza di ciò che si chiama un cellulare è. Dobbiamo dire. Sed comando di sostituzione (s) è spiegato nel profondo dettagli in sed manuale che vi sarà facile trovare (se sono sotto GNU/Linux o macOS provare man sed o, ancora meglio, info sed). Il comando di sostituzione è provato, è sintatticamente corretto, quindi l'errore.
Renaud Pacalet

Yup, che rende più senso, ora, quando lo mettono come che.
Helium
1

Con sed, che ne dite di:

#!/bin/bash

newvalue=3
rownum=4
col=1

sed -i -E "${rownum} s/(([^,]+,){$((col-1))})[^,]+/\\1${newvalue}/" file.csv

Risultato della file.csv

Header,1
Field1,Field2,Field3
1,ABC,4567
3,XYZ,7890
  • ${rownum} corrisponde al numero di riga.
  • (([^,]+,){n}) confronta i n tempo di ripetizione del gruppo di non caratteri virgola seguito da una virgola. Allora dovrebbe essere la sottostringa prima di raggiungere l'obiettivo (da sostituire) colonna assegnando nper col - 1.
2021-11-24 07:21:19

anche se questo non funziona, non è un po ' più complicato modo di fare le cose rispetto a come Renauld risposta. Come perché abbiamo bisogno di abbinare i n tempo di ripetizione se si può invece direttamente sostituirlo? Utile comunque
Helium
0

Cerchiamo di Implementare il comando sed

Consideriamo un esempio di file CSV con il seguente contenuto:

$ cat file

Solaris,25,11
Ubuntu,31,2
Fedora,21,3
LinuxMint,45,4
RedHat,12,5
  1. Per rimuovere il 1 ° campo o colonna :
$ sed 's/[^,]*,//' file

25,11
31,2
21,3
45,4
12,5

Questa espressione regolare la ricerca di una sequenza non la virgola([^,]*) caratteri e li elimina il cui risultato è il 1 ° campo sempre rimosso.

  1. Per stampare solo l'ultimo campo, O rimuovere tutti i campi ad eccezione dell'ultimo campo:
$ sed 's/.*,//' file

11
2
3
4
5

Questa espressione regolare rimuove tutto fino all'ultima virgola(.*,) che si traduce nell'eliminazione di tutti i campi, ad eccezione dell'ultimo campo.

  1. Per stampare solo il 1 ° campo:
$ sed 's/,.*//' file

Solaris
Ubuntu
Fedora
LinuxMint
RedHat

Questa regex(,.*) rimuove i caratteri a partire dal 1 ° comma fino alla fine con conseguente eliminazione di tutti i campi, ad eccezione dell'ultimo campo.

  1. Per eliminare il 2 ° campo:
$ sed 's/,[^,]*,/,/' file

Solaris,11
Ubuntu,2
Fedora,3
LinuxMint,4
RedHat,5

La regex (,[^,]*,) la ricerca di una virgola e la sequenza di caratteri seguita da una virgola, che si traduce in corrispondenza del 2 ° colonna, e sostituisce questo modello abbinato con appena una virgola, in ultima analisi finale l'eliminazione di 2a colonna.

Nota: Per eliminare i campi in mezzo diventa più resistenti in sed poiché ogni campo deve essere abbinato letteralmente.

  1. Per stampare solo il 2 ° campo:
$ sed 's/[^,]*,\([^,]*\).*/\1/' file

25
31
21
45
12

La regex il primo campo, il secondo campo e il resto, per i gruppi 2 ° campo da solo. Tutta la linea è ora sostituito con il 2 ° campo(\1), quindi solo il 2 ° campo viene visualizzato.

  1. Stampa solo le righe in cui l'ultima colonna è un numero di cifra:
$ sed -n '/.*,[0-9]$/p' file

Ubuntu,31,2
Fedora,21,3
LinuxMint,45,4
RedHat,12,5

La regex (,[0-9]$) verifica la presenza di una sola cifra nell'ultimo campo, e il comando p stampe la linea che soddisfa questa condizione.

  1. Per il numero di tutte le righe del file:
$ sed = file | sed 'N;s/\n/ /'

1 Solaris,25,11
2 Ubuntu,31,2
3 Fedora,21,3
4 LinuxMint,45,4
5 RedHat,12,5

Questa è la simulazione del gatto -n comando. awk non è facilmente utilizzando la variabile speciale NR. Il comando '=' della sed dà il numero di riga di ogni linea seguita dalla linea stessa. Sed uscita viene reindirizzato a un altro sed comando per unire ogni 2 righe.

  1. Sostituire l'ultimo campo da 99 se il 1 ° campo è 'Ubuntu':
$ sed 's/\(Ubuntu\)\(,.*,\).*/\1\299/' file

Solaris,25,11
Ubuntu,31,99
Fedora,21,3
LinuxMint,45,4
RedHat,12,5

Questa regex 'Ubuntu' e fino alla fine, tranne l'ultima colonna e gruppi di ognuno di loro. Nella parte di ricambio, 1 ° e 2 ° gruppo con il nuovo numero 99 è sostituito.

  1. Eliminare il 2 ° campo se il 1 ° campo è "RedHat':
$ sed 's/\(RedHat,\)[^,]*\(.*\)/\1\2/' file

Solaris,25,11
Ubuntu,31,2
Fedora,21,3
LinuxMint,45,4
RedHat,,5

Il 1 ° campo "RedHat", il 2 ° campo e i restanti campi sono raggruppati, e la sostituzione è fatto con solo il 1 ° e l'ultimo gruppo , resuting a ottenere il 2 ° campo eliminati.

  1. Per inserire una nuova colonna alla fine(ultima colonna) :
$ sed 's/.*/&,A/' file

Solaris,25,11,A
Ubuntu,31,2,A
Fedora,21,3,A
LinuxMint,45,4,A
RedHat,12,5,A

La regex (.*) le partite di tutta la linea e la sua sostituzione con la linea stessa (&) e il nuovo campo.

  1. Per inserire una nuova colonna di inizio(1 ° colonna):
$ sed 's/.*/A,&/' file

A,Solaris,25,11
A,Ubuntu,31,2
A,Fedora,21,3
A,LinuxMint,45,4
A,RedHat,12,5

Come la scorsa, ad esempio, la linea di corrispondenza è seguita da una nuova colonna

Spero che questo sarà di aiuto. Fatemi sapere se avete bisogno di usare Awk o qualsiasi altro comando. Grazie

2021-11-24 07:36:29

grazie per la spiegazione dettagliata, ma purtroppo non risolve il problema a portata di mano.
Helium

In altre lingue

Questa pagina è in altre lingue

Русский
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................