Colocando todas as linhas que correspondem ao padrão específico no final do arquivo

0

Eu tenho vários arquivos .txt com esta aparência:

XXXXXXXXXXXXXX
NNNNNNNNNNNNNN
NNNNNNNNNNNNNN
NNNNNNNNNNNNN
NNNNNNNNNNNN
NNNNNNNNNNN
XXXXXXXXXXXXXX
XXXXXXXXXXXXX
XXXXXXXXXXXXX
XXXXXXXXXXXX
NNNNNNNNNNNNN
NNNNNNNNNNNN
NNNNNNNNNNNNNN
NNNNNNNNNNNNNN

É possível dar um comando no bash que todas as linhas que começam com N devem terminar no final do arquivo. Então estou esperando algo assim:

XXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXX
NNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNN

.. e para fazer isso em todos os arquivos de uma pasta.

    
por milan 11.01.2018 / 02:59

3 respostas

1

Você pode usar isto:

{
    grep -v '^N' file.txt
    grep '^N' file.txt
} > file.txt.temp
mv file.txt.temp file.txt

Isso funciona combinando todas as linhas que não iniciam com 'N' ( grep -v '^N' ) e, em seguida, todas as linhas que começam com 'N' ( grep '^N' ), exibindo um arquivo temporário e substituindo o original por o arquivo temporário.

Então, se você quiser usar isso em todos os arquivos * .txt em um diretório:

for f in *.txt; do
    {
        grep -v '^N' "$f"
        grep '^N' "$f"
    } > "$f".temp
    mv "$f".temp "$f"
done
    
por wjandrea 11.01.2018 / 04:09
1

Aqui estão algumas opções usando awk

Primeiro, a versão KISS - usando alguns arquivos temporários a e b :

for f in *.txt; do 
  awk '/^N/ {print > "b"; next} {print > "a"}' "$f"
  cat a b > "$f"
done

Só porque. . .

O que você realmente quer fazer é uma classificação no local com uma ordem de classificação personalizada (linhas iniciando com N depois de todo o restante, depois a ordem original), por exemplo, no GNU awk :

function mycmp(ia, a, ib, b) {
  x = substr(a,1,1) == "N"
  y = substr(b,1,1) == "N"
  if (x && !y) return 1
  else if (!x && y) return -1
  else return ia - ib
}

{a[FNR] = $0}

ENDFILE {
  for (i in a) print a[i]
}

As versões mais recentes de gawk fornecem uma extensão in-loco - emprestando a implementação de referência de 16.7.4 Ativando a edição de arquivos no local podemos juntar tudo como um script gawk, Nsort.awk diz:

#!/usr/bin/gawk -f

@load "inplace"

function mycmp(ia, a, ib, b) {
  x = substr(a,1,1) == "N"
  y = substr(b,1,1) == "N"
  if (x && !y) return 1
  else if (!x && y) return -1
  else return ia - ib
}

BEGIN {
  inplace = 1
  INPLACE_SUFFIX = ".bak"
  PROCINFO["sorted_in"] = "mycmp"
}

BEGINFILE {
    if (_inplace_filename != "")
        inplace_end(_inplace_filename, INPLACE_SUFFIX)
    if (inplace)
        inplace_begin(_inplace_filename = FILENAME, INPLACE_SUFFIX)
    else
        _inplace_filename = ""
}

{a[FNR] = $0}

ENDFILE {
  for (i in a) print a[i]
}

END {
    if (_inplace_filename != "")
        inplace_end(_inplace_filename, INPLACE_SUFFIX)
}

Torne-o executável com chmod +x Nsort.awk e execute-o como

./Nsort.awk *.txt
    
por steeldriver 11.01.2018 / 05:33
0

GNU awk (versão 4.1.0 e posterior)

awk -i inplace '/^N/{ printlast = printlast $0 RS ; next } { print $0 } ENDFILE { printf "%s",printlast ; printlast="" }' file1 file2 file3
  1. Use -i inplace para substituir o arquivo original pelo arquivo reordenado. CUIDADO: Isso sobrescreverá arquivos que são somente leitura.
  2. Se uma linha começar com N , anexe a linha ao buffer printlast .
  3. Caso contrário, imprima a linha.
  4. No final do arquivo, imprima o buffer printlast e redefina-o para o próximo arquivo.
  5. Especifique quantos arquivos de entrada você quiser (por exemplo, a.txt b.txt c.txt ou *.txt ).

Substitua -i inplace por -i inplace -v INPLACE_SUFFIX=".bak" para manter uma cópia de cada arquivo original. Neste exemplo, os nomes dos arquivos de cópia de segurança terminarão em .bak .

Outras versões do awk

Se a sua versão de awk não puder editar arquivos no lugar e você não quiser criar arquivos temporários, poderá enviar a saída de awk a sponge (a partir do moreutils pacote):

ls -1 *.txt | \
while read file
do
    chmod +w "${file}"
    awk '/^N/{ printlast = printlast $0 RS ; next } { print $0 } ENDFILE { printf "%s",printlast }' "${file}" | \
    sponge "${file}"
done

Você precisa tornar os arquivos de entrada graváveis - chmod +w "${file}" - para sponge para modificá-los.

    
por Gaultheria 11.01.2018 / 08:30