Как я могу сравнить два файла, используя только две колонки, и распечатать разницу (без сортировки)?

Точно подсчитать, сколько файл действительно занимает на диске, нетривиально, поскольку подробный ответ сложнее, чем просто округлить размер файла до следующего диска блокировать.

А как насчет:

  • жесткой ссылки?
  • экзотической файловой системы, внутреннего способа распределения дискового пространства (выделения половинного блока)?
  • сжатой файловой системы?
  • такой необычной функции, как «дедупликация» ?

Если вы сложите все это, задача станет почти невозможной без надлежащего внутреннего знания того, как все работает на самом деле (так что определенно не простой стат в файле).

Системные инструменты

Однако существует множество системных инструментов, предназначенных для этого или с опциями «занятых блоков». Вот 2 наиболее часто используемых:

  • du

    От man du (из FreeBSD, как более подробный):

     ОПИСАНИЕ 
    Утилита du отображает использование блока файловой системы для каждого аргумента файла 
    и для каждого каталога в файловой иерархии с корнем в каждом аргументе каталога 
    . Если файл не указан, отображается использование блоков иерархии 
    в текущем каталоге. 
     
  • ls -s

    From man ls :

     -s, --size 
    распечатать выделенный размер каждого файла в блоках 
     

    (кажется, ls "блоки" на самом деле устарели Блоки по 1024 байта, а не блоки реального диска)

Пример :

$  dumpe2fs /dev/mapper/vg_centurion-lv_root |head -20 |grep ^Block
dumpe2fs 1.41.12 (17-May-2010)
Block count:              13107200
Block size:               4096

Итак, наша корневая файловая система имеет 4k блоков.

$ ls -l
total 88
-rw-------. 1 root root  2510 Mar 20 18:00 anaconda-ks.cfg
-rw-r--r--. 1 root root 67834 Mar 20 17:59 install.log
-rw-r--r--. 1 root root 12006 Mar 20 17:57 install.log.syslog

С du:

$ du -h anaconda-ks.cfg
4.0K    anaconda-ks.cfg

И ls:

$ ls -ls
total 88
 4 -rw-------. 1 root root  2510 Mar 20 18:00 anaconda-ks.cfg
72 -rw-r--r--. 1 root root 67834 Mar 20 17:59 install.log
12 -rw-r--r--. 1 root root 12006 Mar 20 17:57 install.log.syslog

0
28.01.2019, 21:25
2 ответа

Сawk:

$ awk -v FS="\t" -v OFS="\t" 'NR==FNR {trans[$2"|"$3]++; next;} FNR==1 {print} FNR>1 {if(!trans[$2"|"$3]) print}' file2 file1
  • Сначала считывается file2, и значения столбцов 2 и 3 используются для сохранения их в качестве ключа в списке.
  • Если считывается file1, печатается строка заголовка. Для каждой следующей строки мы проверяем, существует ли ключ со значениями столбцов 2 и 3 в нашем списке, который мы создали ранее. Если нет, мы распечатываем строку.
1
28.01.2020, 02:30

Способ сравнения файлов четко не объяснен/не определен.

Впрочем, это не помешало мне попытаться прочитать ваши мысли...

Насколько я понимаю, файл 2 является своего рода файлом базы данных или ссылкой. Файл 1 предположительно содержит новые данные.

"Сравнение" как я понял :если значение столбца 2 или 3 файла 1 уже найдено в файле 2 (т.е. ссылка ), то не печатать/включать его. В противном случае распечатайте/включите его.

Хорошей новостью является то, что он действительно не требует сортировки... как вы и просили....

Ниже приведен сценарий с двумя параметрами. :Первый — это новый файл данных (файл 1 в вашем примере ). Второй файл базы данных (файл 2 в вашем примере ).

#!/bin/bash

new_file=$1
db_file=$2

# Just checking the last parameter
if [ "x" = "x$db_file" ]; then
    echo >&2 "[ERROR] This scripts expect 2 file path as parameter."
    exit 1
fi

if [ ! -f $new_file ]; then
    echo >&2 "[ERROR] First parameter file doesn't exist."
    exit 2
fi

if [ ! -f $db_file ]; then
    echo >&2 "[ERROR] First parameter file doesn't exist."
    exit 3
fi


declare -A data_base

# Open both files and assign to file descriptor 10 and 11
exec 10< $new_file
exec 11< $db_file

# Step 1
# Building map of base data first (for the comparison to happen in next step)
first_line=1
while [ /bin/true ]; 
do
    read -u 11 db_file_col1 db_file_col2 db_file_col3 db_file_rest  || {
        break;
    }

    # Skipping the header so that it will appear in the diff as shown in the example
    if [  $first_line -ne 0 ]; then
        first_line=0
        continue
    fi


    # Creating map from Col 2 and Col 3 (keys) to the whole line (value)
    data_base[$db_file_col2]="$db_file_col1 $db_file_col2 $db_file_col3 $db_file_rest"
    data_base[$db_file_col3]="$db_file_col1 $db_file_col2 $db_file_col3 $db_file_rest"
done


# Step 2
# Actual comparison... 
while [ /bin/true ]; 
do
    read -u 10 new_file_col1 new_file_col2 new_file_col3 new_file_rest  || {
        break;
    }

    if [ -z "${data_base[$new_file_col2]}" ] && [ -z "${data_base[$new_file_col3]}" ]; then
        echo "$new_file_col1 $new_file_col2 $new_file_col3 $new_file_rest"
    fi

done

Если вы сохраните скрипт в файл с именем process.sh, например (, а затем выполните команду chmod 755 process.sh, чтобы сделать его исполняемым ), то выполнение:

./process.sh file1 file2 

в то время как привести к вашему точному ожидаемому выходу/результату.

ПРИМЕЧАНИЕ. :Этот сценарий удерживает в памяти как минимум вдвое больше содержимого файла 2. Убедитесь, что у вас достаточно памяти....

1
28.01.2020, 02:30

Теги

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