Respostas:
A -F
opção precisa de um argumento: -F,
por exemplo.
O final do awk
script deve ser separado por um (caractere de espaço) com o restante dos parâmetros.
Se o separador de campos for ,
e você deseja mantê-lo, e se o número de colunas for constante e menor que ou igual a 11, tente isso:
awk -F, '{print $1,$2,$3,$4,$5,$6,$8,$9,$10,$11,$7}' OFS=, "$file"
command file > newfile && mv newfile file
. Dito isto, a versão mais recente do GNU awk
para apoiar este: gawk -i inplace '{blah blah}' file
.
mv newfile file
você pode usar cat newfile > file ; rm -f newfile
- isso preserva o inode e as permissões de file
.
mktemp
vez de codificar, nomes de arquivos temporários em scripts. por exemplotf=$(mktemp) ; command file > "$tf" ; cat "$tf" > file ; rm -f "$tf"
Solução mais curta seria
awk -F',+' -v OFS=, '{$(NF+1)=$7; $7=""; $0=$0; $1=$1}1' file
Não tenho certeza se ,+
funcionará em todas as awk
versões, mas funciona pelo menos no GNU awk, também com o -c
modo de compatibilidade.
Explicação:
$(NF+1)=$7
: primeiro, adicionamos o sétimo campo ao final da linha (pode ser $12=$7
neste caso)$7=""
: na próxima etapa, o 7º campo é apagado (mas os delimitadores circundantes permanecem)$0=$0
) tratando várias vírgulas como separador de campo (isso é feito via -F',+'
, aqui +
significa uma ou mais vezes) e também reorganizar o registro atual via $1=$1
para forçar a reconstrução da linha usando o campo de saída definido anteriormente separador (definido por uma opção -v OFS=,
)1
Exemplo de entrada:
1,2,3,4,5,6,7,8,9,10,11
resultado
1,2,3,4,5,6,8,9,10,11,7
,+
deve funcionar.
all,ball,call,,,fall
→ all,ball,call,fall
). (2) $(NF+1)=$7
é uma abordagem inteligente. IMHO, $0 = $0 OFS $7
é um pouco mais claro, apenas alguns caracteres a mais, e parece fazer a mesma coisa. Você consegue pensar em uma situação em que $0 = $0 OFS $7
não faça o mesmo que o seu código?
$0=$0 OFS $7
provavelmente é idêntico a $(NF+1)=$7
, mas apenas com o restante do código inalterado, não em geral.
Se estiver imprimindo com OFS=
, portanto, sem separador entre os campos, você pode simplesmente salvar o valor de $7
em uma variável, definido $7
como vazio e imprimir a linha e a variável diretamente. Você não precisa especificar todos os campos:
$ cat file
1,2,3,4,5,6,7,8
$ awk -F, -vOFS= '{k=$7; $7=""; print $0,k}' file
12345687
Você provavelmente quer dizer:
awk -F, -v OFS='' '{print $1,$2,$3,$4,$5,$6,$8,$9,$10,$11,$7}' "$file"
awk
nunca vê as aspas simples OFS=''
, certo? Você também pode digitar OFS=
; é exatamente o mesmo.
Você não diz especificamente que você queria usar awk, e você me disse que queria usar a edição no local, como fornecido pelo sed -i
, então aqui é uma sed -i
variante. Geralmente awk
é melhor trabalhar com colunas, mas esse é um caso em que eu prefiro sed
, porque naturalmente lida com números arbitrários de colunas.
MOVECOL=7
N=$((MOVECOL-1))
sed -r -e "s/^(([^,]*,){$N})([^,]*),(.*)/\1\4,\3/" -i test.csv
Explicação:
-r
seleciona regexps estendidos, para evitar muitas barras invertidasÉ claro que isso não funcionará com arquivos que ocultam vírgulas entre aspas (ou pior, escapam), mas o awk também não lidará com isso sem algumas acrobacias sérias. Se você tiver esse problema, seria melhor usar o perl
módulo Text:CSV
ou o python
módulo csv
.
Algumas awk
variantes (supondo que seu arquivo esteja dentro da variável $file
)
Aqui você pode pedalar por toda a cor, imprimir com o separador de campos (OFS) e imprimir o terminador de registro (ORS) no final da linha.
awk -F',' -v OFS=, \
'{for(i=1;i<=NF;i++) if (i!=7) printf "%s",$i OFS; \
printf "%s",$7;printf ORS}' "$file"
Aqui com o uso de um regex e a gensub()
função
gawk -F',+' -v OFS=, '{$0=gensub(/\s*\S+/,"",7) OFS $7}1' "$file"
matando o 7º campo e imprimindo no final da linha.
$0
é todo o registro $n
é o nono registro NF
é o número de campos da linha atual OFS
o separador arquivado de saídaORS
o terminador do registro de saída1
é o truque a ser dito para ativar true
e imprimir o padrão ( $0
).Atualizar ...
Quase esqueço que é possível mudar todas as colunas após a 7ª .
awk -F',' -v OFS=, '{tmp=$7; for(i=7;i<=NF;i++) $i=$(i+1); $NF=tmp}1 ' "$file"
OFS $7
seria mais robusto que "," $7
. (2) Eu acredito que ", " $7
é errado, na medida em que a questão indica que o OP não quer espaços após as vírgulas. (E, se os dados de entrada tivessem espaços após as vírgulas, $7
eles já começariam com um espaço e você incluiria um adicional.)
OFS $7
, não só mais robusta, mas ainda mais geral ( "pressa deixa resíduos" )
^
indica a parte específica do comando onde o erro foi encontrado.