Risposte:
L' -F
opzione ha bisogno di un argomento: -F,
ad esempio.
La fine dello awk
script deve essere separata con un (space char) con il resto dei parametri.
Se il separatore di campo è ,
e si desidera mantenerlo e se il numero di colonne è costante e inferiore o uguale a 11, provare a questo:
awk -F, '{print $1,$2,$3,$4,$5,$6,$8,$9,$10,$11,$7}' OFS=, "$file"
command file > newfile && mv newfile file
. Detto questo, la versione più recente di GNU awk
per sostenere questo: gawk -i inplace '{blah blah}' file
.
mv newfile file
te puoi usare cat newfile > file ; rm -f newfile
- questo conserva l'inode e le autorizzazioni di file
.
mktemp
piuttosto che codificare i nomi dei file temporanei negli script. ad esempiotf=$(mktemp) ; command file > "$tf" ; cat "$tf" > file ; rm -f "$tf"
La soluzione più breve sarebbe
awk -F',+' -v OFS=, '{$(NF+1)=$7; $7=""; $0=$0; $1=$1}1' file
Non sono sicuro ,+
che funzionerà in tutte le awk
versioni, ma funziona almeno in awk GNU, anche con la -c
modalità ompatibilità.
Spiegazione:
$(NF+1)=$7
: prima aggiungiamo il 7 ° campo alla fine della riga (potrebbe essere $12=$7
in questo caso)$7=""
: nel passaggio successivo il 7 ° campo viene cancellato (ma i delimitatori circostanti rimangono)$0=$0
) trattando più virgole come separatore di campo (questo viene fatto tramite -F',+'
, qui +
significa una o più volte), e anche riorganizzare il record corrente tramite $1=$1
per forzare la ricostruzione della linea utilizzando il campo di output precedentemente impostato separatore (impostato da un'opzione -v OFS=,
)1
Esempio di input:
1,2,3,4,5,6,7,8,9,10,11
produzione
1,2,3,4,5,6,8,9,10,11,7
,+
dovrebbe funzionare.
all,ball,call,,,fall
→ all,ball,call,fall
). (2) $(NF+1)=$7
è un approccio intelligente. IMHO, $0 = $0 OFS $7
è un po 'più chiaro, solo un paio di personaggi in più, e sembra fare la stessa cosa. Riesci a pensare a una situazione in cui $0 = $0 OFS $7
non fa lo stesso del tuo codice?
$0=$0 OFS $7
è probabilmente identico a $(NF+1)=$7
, ma solo con il resto del codice invariato, non in generale.
Se stai stampando con OFS=
, quindi senza un separatore tra i campi, puoi semplicemente salvare il valore di $7
in una variabile, impostare $7
su vuoto e stampare direttamente la linea e la variabile. Non è necessario specificare tutti i campi:
$ cat file
1,2,3,4,5,6,7,8
$ awk -F, -vOFS= '{k=$7; $7=""; print $0,k}' file
12345687
Probabilmente intendi:
awk -F, -v OFS='' '{print $1,$2,$3,$4,$5,$6,$8,$9,$10,$11,$7}' "$file"
awk
non vede mai le virgolette singole OFS=''
, giusto? Puoi anche solo digitare OFS=
; è esattamente lo stesso.
Lei non ha espressamente detto che volevi usare awk, e hai detto che volevi usare la modifica sul posto come fornito da sed -i
, ecco un sed -i
variante. Di solito awk
è meglio per lavorare con le colonne, ma questo è un caso in cui preferisco sed
, perché gestisce naturalmente un numero arbitrario di colonne.
MOVECOL=7
N=$((MOVECOL-1))
sed -r -e "s/^(([^,]*,){$N})([^,]*),(.*)/\1\4,\3/" -i test.csv
Spiegazione:
-r
seleziona regexps estesi in modo da evitare molte barre rovesciateNaturalmente questo non funzionerà con i file che nascondono le virgole tra virgolette (o peggio, sfuggirle), ma awk non lo gestirà senza alcune acrobazie serie. Se hai questo problema, staresti meglio con il perl
modulo Text:CSV
o il python
modulo csv
.
Un paio di awk
varianti (supponendo che il tuo file sia all'interno della variabile $file
)
Qui è possibile scorrere per tutta la colonna, stampare con il separatore di campo (OFS) e stampare il terminatore di registrazione (ORS) alla fine della riga.
awk -F',' -v OFS=, \
'{for(i=1;i<=NF;i++) if (i!=7) printf "%s",$i OFS; \
printf "%s",$7;printf ORS}' "$file"
Qui con l'utilizzo di una regex e la gensub()
funzione
gawk -F',+' -v OFS=, '{$0=gensub(/\s*\S+/,"",7) OFS $7}1' "$file"
uccidendo il 7 ° campo e stampandolo alla fine della riga.
$0
è l'intero record $n
è l' ennesimo record NF
è il numero di campi della riga corrente OFS
il separatore archiviato in uscitaORS
il terminatore del record di output1
è il trucco per dire di awk true
e stampare il valore predefinito ( $0
).Aggiorna ...
Quasi dimentico, è possibile spostare tutte le colonne seguendo la settima .
awk -F',' -v OFS=, '{tmp=$7; for(i=7;i<=NF;i++) $i=$(i+1); $NF=tmp}1 ' "$file"
OFS $7
sarebbe più robusto di "," $7
. (2) Credo che ", " $7
sia sbagliato, in quanto la domanda indica che l'OP non vuole spazi dopo le virgole. (E, se i dati di input avessero spazi dopo le virgole, allora $7
inizierebbero già con uno spazio e ne aggiungeresti uno in più.)
OFS $7
, non solo più robusto, ma anche più generale ( "la fretta fa sprecare" )
^
indica la parte specifica del comando in cui è stato rilevato l'errore.