Réponses:
L' -F
option a besoin d'un argument: -F,
par exemple.
La fin du awk
script doit être séparée par un (caractère espace) avec le reste des paramètres.
Si le séparateur de champ est ,
et que vous souhaitez le conserver, et si le nombre de colonnes est constant et inférieur ou égal à 11, essayez ceci:
awk -F, '{print $1,$2,$3,$4,$5,$6,$8,$9,$10,$11,$7}' OFS=, "$file"
command file > newfile && mv newfile file
. Cela dit, la version plus récente de GNU awk
pour soutenir ceci: gawk -i inplace '{blah blah}' file
.
mv newfile file
vous pouvez utiliser cat newfile > file ; rm -f newfile
- cela préserve l'inode et les autorisations de file
.
mktemp
plutôt que de coder en dur les noms de fichiers temporaires dans les scripts. par exempletf=$(mktemp) ; command file > "$tf" ; cat "$tf" > file ; rm -f "$tf"
Une solution plus courte serait
awk -F',+' -v OFS=, '{$(NF+1)=$7; $7=""; $0=$0; $1=$1}1' file
Je ne sais pas si ,+
cela fonctionnera dans toutes les awk
versions, mais fonctionne au moins dans GNU awk, également avec le -c
mode de compatibilité.
Explication:
$(NF+1)=$7
: nous ajoutons d'abord le 7ème champ à la fin de la ligne (pourrait être $12=$7
dans ce cas)$7=""
: à l'étape suivante, le 7ème champ est effacé (mais les délimiteurs environnants restent)$0=$0
) en traitant plusieurs virgules comme séparateur de champ (cela se fait via -F',+'
, +
signifie ici une ou plusieurs fois), et également réorganiser l'enregistrement actuel via $1=$1
pour forcer la reconstruction de la ligne en utilisant le champ de sortie précédemment défini séparateur (défini par une option -v OFS=,
)1
Exemple d'entrée:
1,2,3,4,5,6,7,8,9,10,11
production
1,2,3,4,5,6,8,9,10,11,7
,+
devrait donc fonctionner.
all,ball,call,,,fall
→ all,ball,call,fall
). (2) $(NF+1)=$7
est une approche intelligente. À mon humble avis, $0 = $0 OFS $7
est un peu plus clair, seulement quelques caractères de plus, et il semble faire la même chose. Pouvez-vous penser à une situation dans laquelle $0 = $0 OFS $7
ne fait pas la même chose que votre code?
$0=$0 OFS $7
est probablement identique à $(NF+1)=$7
, mais uniquement avec le reste du code inchangé, pas en général.
Si vous imprimez avec OFS=
, donc sans séparateur entre les champs, vous pouvez simplement enregistrer la valeur de $7
dans une variable, définie $7
sur vide et imprimer directement la ligne et la variable. Vous n'avez pas besoin de spécifier tous les champs:
$ cat file
1,2,3,4,5,6,7,8
$ awk -F, -vOFS= '{k=$7; $7=""; print $0,k}' file
12345687
Vous voulez probablement dire:
awk -F, -v OFS='' '{print $1,$2,$3,$4,$5,$6,$8,$9,$10,$11,$7}' "$file"
awk
ne voit jamais les guillemets simples OFS=''
, non? Vous pouvez aussi bien taper OFS=
; c'est exactement pareil.
Vous n'avez pas dit spécifiquement que vous vouliez utiliser awk, et vous avez dit que vous vouliez utiliser l' édition en place comme prévu par sed -i
, alors voici une sed -i
variante. Il awk
est généralement préférable de travailler avec des colonnes, mais c'est un cas où je préfère sed
, car il gère naturellement des nombres arbitraires de colonnes.
MOVECOL=7
N=$((MOVECOL-1))
sed -r -e "s/^(([^,]*,){$N})([^,]*),(.*)/\1\4,\3/" -i test.csv
Explication:
-r
sélectionne des expressions régulières étendues afin d'éviter de nombreuses contre-obliquesBien sûr, cela ne fonctionnera pas avec des fichiers qui cachent des virgules entre guillemets (ou pire, les échappent), mais awk ne s'en occupera pas non plus sans quelques acrobaties sérieuses. Si vous avez ce problème, vous feriez mieux avec le perl
module Text:CSV
ou le python
module csv
.
Quelques awk
variantes (en supposant que votre fichier se trouve à l'intérieur de la variable $file
)
Ici, vous pouvez faire défiler toutes les colonnes, imprimer avec le séparateur de champ (OFS) et imprimer le terminateur d'enregistrement (ORS) à la fin de la ligne.
awk -F',' -v OFS=, \
'{for(i=1;i<=NF;i++) if (i!=7) printf "%s",$i OFS; \
printf "%s",$7;printf ORS}' "$file"
Ici avec l'utilisation d'une expression régulière et de la gensub()
fonction
gawk -F',+' -v OFS=, '{$0=gensub(/\s*\S+/,"",7) OFS $7}1' "$file"
tuer le 7 e champ et l'imprimer à la fin de la ligne.
$0
est tout le record $n
est le nième record NF
est le nombre de champs de la ligne courante OFS
le séparateur déposé en sortieORS
le terminateur d'enregistrement de sortie1
est l'astuce pour dire awk true
et imprimer la valeur par défaut ( $0
).Mettre à jour ...
J'oublie presque, il est possible de décaler toutes les colonnes après la 7 ème .
awk -F',' -v OFS=, '{tmp=$7; for(i=7;i<=NF;i++) $i=$(i+1); $NF=tmp}1 ' "$file"
OFS $7
serait plus robuste que "," $7
. (2) Je pense que ", " $7
c'est faux, dans la mesure où la question indique que l'OP ne veut pas d'espaces après les virgules. (Et, si les données d'entrée avaient des espaces après les virgules, alors $7
commenceraient déjà par un espace, et vous en ajouteriez un supplémentaire.)
OFS $7
, non seulement plus robuste, mais encore plus général ( "la hâte fait gaspiller" )
^
indique la partie spécifique de la commande où l'erreur a été rencontrée.