Поместить все строки, которые соответствуют определенному шаблону в конце файла

У меня есть несколько файлов .txt, которые выглядят так:

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

Можно ли дать команду в bash, что все строки, начинающиеся с N, должны заканчиваться в конце файла , Поэтому я ожидаю что-то вроде этого:

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

.. и сделать это для всех файлов из одной папки.

0
задан 11 January 2018 в 04:59

3 ответа

Вы можете использовать это:

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

Это работает, сопоставляя все строки, которые не начинаются с 'N' (grep -v '^N'), затем сопоставляя все строки, которые начинаются с 'N' (grep '^N'), выводя во временный файл, затем заменяя оригинал временным файлом.

Тогда, если вы хотите использовать это для всех * .txt файлов в каталоге:

for f in *.txt; do
    {
        grep -v '^N' "$f"
        grep '^N' "$f"
    } > "$f".temp
    mv "$f".temp "$f"
done
1
ответ дан 11 January 2018 в 04:59

Вот несколько использований опций awk

Во-первых, версия KISS - использование нескольких временных файлов a и b:

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

Просто так...

То, что Вы действительно хотите сделать, является оперативным видом с пользовательским порядком сортировки (строки, запускающиеся с N после всего остального, затем первоначальный заказ), например, в 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]
}

Более новые версии gawk обеспечьте оперативное расширение - заимствование ссылочной реализации от 16.7.4 Включающих Оперативных Редактирований Файла, мы можем соединить все это как сценарий простофили, Nsort.awk скажите:

#!/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)
}

Сделайте это исполняемым файлом с chmod +x Nsort.awk и выполненный это как

./Nsort.awk *.txt
1
ответ дан 11 January 2018 в 04:59

GNU awk (версия 4.1.0 и позже)

awk -i inplace '/^N/{ printlast = printlast $0 RS ; next } { print $0 } ENDFILE { printf "%s",printlast ; printlast="" }' file1 file2 file3
  1. Использовать -i inplace заменять исходный файл переупорядоченным файлом.Внимание: Это перезапишет файлы, которые установлены только для чтения.
  2. Если строка запускается с N, добавьте строку к буферу printlast.
  3. Иначе распечатайте строку.
  4. В конце файла распечатайте буфер printlast, затем сбросьте его для следующего файла.
  5. Укажите столько входных файлов, сколько Вы хотите (например, a.txt b.txt c.txt или *.txt).

Замена -i inplace с -i inplace -v INPLACE_SUFFIX=".bak" сохранять копию каждого исходного файла. В этом примере имена файлов резервной копии все закончатся в .bak.

Другие версии awk

Если Ваша версия awk не может отредактировать файлы на месте, и если Вы не хотите создавать временные файлы, затем можно передать вывод по каналу awk через sponge (от moreutils пакет):

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

Необходимо сделать входные файлы перезаписываемыми- chmod +w "${file}" - для sponge изменить их.

0
ответ дан 11 January 2018 в 04:59

Другие вопросы по тегам:

Похожие вопросы: