Сравните каталоги, но не содержание файлов

Примечание о некоторых более легких реализациях (телефоны на базе Android, busybox, и т.д.): ps не всегда имеет поддержку -p переключатель, но можно выполнить поиск с командой как ps | grep "^$$ ". (Это grep regex однозначно определит PID, таким образом, не будет никаких ложных положительных сторон.

23
07.09.2016, 03:54
10 ответов

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

rsync -n -a -i --delete source/ target/

объяснение:

  • -n фактически не копировать и не удалять <- ЭТО ВАЖНО !! 1
  • -a сравнить все метаданные файла, такие как временная метка и атрибуты
  • -i выводит по одной строке информации для каждого файла
  • - удаление также сообщает о файлах, которых нет в исходном

примечании: важно добавлять имена каталогов с помощью косой черты. это вещь rsync.

, если вы также хотите видеть строки, напечатанные для идентичных файлов, предоставьте -i дважды

rsync -n -a -ii --delete source/ target/

пример вывода:

*deleting   removedfile   (file in target but not in source)
.d..t...... ./            (directory with different timestamp)
>f.st...... modifiedfile  (file with different size and timestamp)
>f+++++++++ newfile       (file in source but not in target)
.f          samefile      (file that has same metadata. only with -ii)

помните, что rsync сравнивает только метаданные. это означает, что если содержимое файла изменилось, но метаданные остались прежними, rsync сообщит, что файл такой же. это маловероятный сценарий. так что либо верьте, что, когда метаданные одинаковы, тогда данные такие же, либо вам придется сравнивать данные файла побитно.

бонус: информацию о ходе выполнения см. Здесь: Оценить время или работу, оставшуюся до завершения для rsync?

24
27.01.2020, 19:42

Используйте -q (--brief) опция с diff -r (diff -qr). От info страница для GNU diff:

1.6 Суммирование, какие файлы отличаются

Когда Вы только хотите узнать, отличаются ли файлы, и Вы не заботитесь, каковы различия, можно использовать сводный выходной формат. В этом формате, вместо того, чтобы показать различия между файлами, diff' simply reports whether files differ. The- резюме' ('-q') опция выбирает этот выходной формат.

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

Это не выдержит сравнение линию за линией, а скорее файл в целом, который значительно ускоряет процессор (что' Вы ищете).

3
27.01.2020, 19:42
  • 1
    Проблема - q состоит в том, что это выдерживает сравнение нормальный и когда находит, что различие останавливается (если был нормальный режим, это продолжает выдерживать сравнение), поэтому если огромные файлы будут тем же, то это продлится много. –  eez0 24.12.2012, 20:34

Вот быстрый сценарий Python, который проверит, что имена файлов, mtimes, и размеры файла являются всеми одинаковыми:

import os
import sys

def getStats(path):
    for pathname, dirnames, filenames in os.walk(path):
        for filename in ( os.path.join(pathname, x) for x in filenames ):
            stat = os.stat(filename)
            yield filename[len(path):], stat.st_mtime, stat.st_size

sys.exit(tuple(getStats(sys.argv[1])) != tuple(getStats(sys.argv[2])))
3
27.01.2020, 19:42

Если требуется сравнить только структуру и некоторую основную информацию о файлах, можно попробовать что-то вроде этого:

diff <(cd $DIR1 && ls -laR) <(cd $DIR2 && ls -laR)

Я не протестировал его, таким образом, любые редактирования приветствуются :)

0
27.01.2020, 19:42
  • 1
    , Это не будет работать самими именами каталогов, также будет в результатах. –  Chris Down 24.12.2012, 21:05
  • 2
    , что, если мы исключим первый столбец с именами каталогов? как <(ls-laR | awk '{1$ = ""; печать}') –  Volodymyr 24.12.2012, 21:23
  • 3
    Не все строки являются именами каталогов, так, чтобы не работал правильно. А-ч –  Chris Down 24.12.2012, 22:19
  • 4
    Используйте в своих интересах то, что каждый <() имеет его собственную среду. Отредактированный. –  a CVn 11.12.2016, 14:43

Основанный на сценарии Криса Дауна, этот сценарий немного более "нагляден". Вызывая его с двумя аргументами папка1 и папка2 , он обходит первую папку и для каждого файла ищет соответствующий файл во второй папке. Если он найден, относительный путь печатается зеленым цветом, если у них другое время изменения или размер, он печатается желтым цветом, а если он не найден, он печатается красным.

#!/usr/bin/env python

import os
import sys
from termcolor import colored

def compare_filestats(file1,file2):
    """
    Compares modified time and size between two files.
    Return:
        -1 if file1 or file2 does not exist
         0 if they exist and compare equal
         1 if they have different modified time, but same size
         2 if they have different size, but same modified time
         3 if they have different size, and different modified time
    """

    if not os.path.exists(file1) or not os.path.exists(file2):
        return -1

    stat1 = os.stat(file1)
    stat2 = os.stat(file2)

    return (stat1.st_mtime != stat2.st_mtime) \
        + 2*(stat1.st_size != stat2.st_size)

def compare_folders(folder1,folder2):
    """
    folder1: serves as reference and will be walked through
    folder2: serves as target and will be querried for each file in folder1

    Prints colored status for each file in folder1:
        missing: file was not found in folder2 
        mtime  : modified time is different
        size   : filesize is different
        ok     : found with same filestats
    """
    for dirpath, dirnames, filenames in os.walk(folder1):
        for file1 in ( os.path.join(dirpath, x) for x in filenames ):
            relpath = file1[len(folder1):]
            file2 = os.path.join( folder2, relpath )
            comp = compare_filestats(file1,file2)

            if comp < 0:
                status = colored('[missing]','red')
            elif comp == 1:
                status = colored('[mtime  ]','yellow')
            elif comp >= 2:
                status = colored('[size   ]','yellow')
            else:
                status = colored('[ok     ]','green')

            print status, relpath

if __name__ == '__main__':
    compare_folders(sys.argv[1],sys.argv[2])

Обратите внимание, что этого недостаточно , чтобы решить, являются ли две папки одинаковыми, вам нужно будет запустить его обоими способами, чтобы убедиться. На практике, если вы просто хотите узнать , совпадают ли папки , то сценарий Криса лучше.Если вы хотите знать , что отсутствует или отличается от одной папки к другой , то мой сценарий скажет вам.

ПРИМЕЧАНИЕ: вам потребуется установить termcolor, pip install termcolor .

0
27.01.2020, 19:42

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

find /opt/branch1 -type f | sort | xargs -i md5sum {} >/tmp/branch1;
find /opt/branch2 -type f | sort | xargs -i md5sum {} >/tmp/branch2;
diff /tmp/branch1 /tmp/branch2;

ХТХ

2
27.01.2020, 19:42

Сохранить следующий код как:diffm.sh:

# DIFF with Modification date - a.sh (dash; bash; zsh - compatible) 
# "diff utility"-like script that can compare files in two directory 
# trees by path, size and modification date

# Disclaimer:
# By using this program you are assuming full responsibility (and the 
# author of this program shall not be held liable) for any data loss 
# or damage that may result from the use or misuse of this program.


Proc1 () {
    new="$line"
    first_remaining_part="${new%"///////"*}"
    time="${first_remaining_part#*"///////"}"
    first_part="${new%%" ///////"*}"
    #last_part="${new##*"///////"}"

    seconds_since_epoch="${new##*" "}"
    #convert seconds_since_epoch to base 10 (remove 0's padding):
    temp="${seconds_since_epoch#"0"*[1-9]}"
    zeros="${seconds_since_epoch%"$temp"}"
    zeros="${zeros%?}" #Remove last non-0 digit
    seconds_since_epoch="${seconds_since_epoch#"$zeros"}"

    time_zone="${time##*" "}"
    time="${time%"."*}"

    new="$first_part ///// $time $time_zone ///// $seconds_since_epoch"

    printf '%s\n' "$new"
}

Proc2 () {
    cd "$dir1" >/dev/null 2>/dev/null

    count_files=0

    {
        IFS="
"
        set -f
        #FilePath / FileType / FileSize / FileTime / SecondsSinceEpoch
        if [ "$OS" = "Linux" -o "$OS" = "Windows" ]; then
            find. -not -type d -printf '%p ///// <_ ///// %s ///////%TY-%Tm-%Td %TT %Tz///////' -exec stat --printf ' %Y\n' {} \; 2>/dev/null|\
            {\
            while read line; do {\
                count_files=$((count_files + 1));\
                PrintJustInTitle "Analyzing file $count_files...";\
                Proc1;\
            }; done;\
            printf "$count_files">$RAMLocation/diffm_count.txt;\
            }
        elif [ "$OS" = "Mac" ]; then
            gfind. -not -type d -printf '%p ///// <_ ///// %s ///////%TY-%Tm-%Td %TT %Tz///////' -exec gstat --printf ' %Y\n' {} \; 2>/dev/null|\
            {\
            while read line; do {\
                count_files=$((count_files + 1));\
                PrintJustInTitle "Analyzing file $count_files...";\
                Proc1;\
            }; done;\
            printf "$count_files">$RAMLocation/diffm_count.txt;\
            }
        fi
        unset IFS
        set +f
    }

    cd "$initial_dir"
}

Proc3 () {
    cd "$dir2" >/dev/null 2>/dev/null

    #Get previous line count value from diffm_count.txt:
    read count_files<"$RAMLocation/diffm_count.txt"
    #Validate count_files as a number:
    count_files=$((count_files))

    {
        IFS="
"
        set -f
        #FilePath / FileType / FileSize / FileTime / SecondsSinceEpoch
        if [ "$OS" = "Linux" -o "$OS" = "Windows" ]; then
            find. -not -type d -printf '%p ///// >_ ///// %s ///////%TY-%Tm-%Td %TT %Tz///////' -exec stat --printf ' %Y\n' {} \; 2>/dev/null|\
            {\
            while read line; do {\
                count_files=$((count_files + 1));\
                PrintJustInTitle "Analyzing file $count_files...";\
                Proc1;\
            }; done;\
            printf "$count_files">$RAMLocation/diffm_count.txt;\
            }
        elif [ "$OS" = "Mac" ]; then
            gfind. -not -type d -printf '%p ///// >_ ///// %s ///////%TY-%Tm-%Td %TT %Tz///////' -exec gstat --printf ' %Y\n' {} \; 2>/dev/null|\
            {\
            while read line; do {\
                count_files=$((count_files + 1));\
                PrintJustInTitle "Analyzing file $count_files...";\
                Proc1;\
            }; done;\
            printf "$count_files">$RAMLocation/diffm_count.txt;\
            }
        fi
        unset IFS
        set +f
    }

    #Get total line count value from diffm_count.txt:
    read count_files<"$RAMLocation/diffm_count.txt"
    #Validate count_files as a number:
    count_files=$((count_files))

    #"." in front of the number is for displaying it as first line after the sort operation:
    printf ".$count_files"

    cd "$initial_dir"
}

GetOS () {
    OS_kernel_name=$(uname -s)

    case "$OS_kernel_name" in
        "Linux")
            eval $1="Linux"
        ;;
        "Darwin")
            eval $1="Mac"
        ;;
        "CYGWIN"*|"MSYS"*|"MINGW"*)
            eval $1="Windows"
        ;;
        "")
            eval $1="unknown"
        ;;
        *)
            eval $1="other"
        ;;
    esac
}

PrintInTitle () {
    printf "\033]0;%s\007" "$1"
}

PrintJustInTitle () {
    PrintInTitle "$1">/dev/tty
}

trap1 () {
    CleanUp
    printf "\nAborted.\n">/dev/tty
}

CleanUp () {
    #Clear the title:
    PrintJustInTitle ""
    #Restore "INTERRUPT" (CTRL-C) and "TERMINAL STOP" (CTRL-Z) signals:
    trap - INT
    trap - TSTP
}

GetSetRAMLocation () {
    GetOS OS
    if [ "$OS" = "Linux" ]; then
        RAMLocation='/dev/shm'
    elif [ "$OS" = "Mac" ]; then
        RAMLocation='/Volumes/RamDiskDIFFM'
        sizeInMB = "1"
        if [ ! -e "/Volumes/RamDiskDIFFM" ]; then
            diskutil partitionDisk $(hdiutil attach -nomount ram://$((2048*sizeInMB))) 1 GPTFormat APFS 'RamDiskDIFFM' '100%'&&{
                printf "">"$RAMLocation/diffm_count.txt"&&{
                    error="false"
                }||{
                    printf '\n%s\n\n' "Error: Could not write to RAM (\"$RAMLocation/diffm_count.txt\"). Write to current directory instead? [ Yes (=continue) / No (=Enter=abort) ]">/dev/tty
                    read answer
                    case "$answer" in
                        "Y"|"y"|"Yes"|"yes")
                            answer="yes"
                        ;;
                        "N"|"n"|"No"|"no")
                            answer="no"
                        ;;
                        "")
                            answer="no"
                        ;;
                        *)
                            answer="no"
                        ;;
                    esac
                    if [ "$answer" = "yes" ]; then
                        RAMLocation="$initial_dir"
                        error="false"
                    elif [ "$answer" = "no" ]; then
                        printf "\nAborted.\n\n">/dev/tty
                        error="true"
                    fi
                }
            }||{
                printf '\n%s\n\n' "ERROR: Could not create RAM Volume!">/dev/tty
                error="true"
            }
        fi
        if [ "$error" = "true" ]; then
            CleanUp
            exit 1
        fi
    elif [ "$OS" = "Windows" ]; then
        #On Windows, the RAMLocation variable is not currently designed to point to a RAM Drive path:
        RAMLocation="$initial_dir"
    elif [ $OS" = "other ]; then
        #On other operating systems, the RAMLocation variable is not currently designed to point to a RAM Drive path:
        RAMLocation="$initial_dir"
    else
        printf '\n%s\n\n' "ERROR: Could not get OS!">/dev/stderr
        CleanUp
        exit 1
    fi
}

DestroyArray () {
    eval array_len=\$\(\($1\_0\)\)

    j=0;
    while [ "$j" -lt "$array_len" ]; do
        j=$((j+1))
        unset $1\_$j
    done
    unset $1\_0
}

DisplayHelp () {
    printf "\n"
    printf "diffm - DIFF with Modification date\n"
    printf "\n"
    printf "    What it does:\n"
    printf "        - compares the files (recursively) in the two provided directory tree paths (<dir_tree1> and <dir_tree2>) by:\n"
    printf "            1. Path\n"
    printf "            2. Size\n"
    printf "            3. Modification date\n"
    printf "    Syntax:\n"
    printf "        <caller_shell> '/path/to/diffm.sh' <dir_tree1> <dir_tree2> [flags]\n"
    printf "        - where:\n"
    printf "            - <caller_shell> can be any of the shells: dash, bash, zsh, or any other shell compatible with the \"dash\" shell syntax\n"
    printf "            - '/path/to/diffm.sh' represents the path of this script\n"
    printf "            - <dir_tree1> and <dir_tree2> represent the directory trees to be compared\n"
    printf "            - [flags] can be:\n"
    printf "                --help or -h\n"
    printf "                    Displays this help information\n"
    printf "    Output:\n"
    printf "        - lines starting with '<' signify files from <dir_tree1>\n"
    printf "        - lines starting with '>' signify files from <dir_tree2>\n"
    printf "    Notes:\n"
    printf "        - only files in the two provided directory tree paths are compared, not also directories\n"
    printf "\n"
}

##################
### MAIN START ###
##################

GetOS OS

if [ "$OS" = "Linux" -o "$OS" = "Windows" ]; then
    error1="false"
    error2="false"
    error3="false"

    { sort --version-sort --help >/dev/null 2>/dev/null; } || { error1="true"; }
    { stat --help >/dev/null 2>/dev/null; } ||  { error2="true"; }
    { find --help >/dev/null 2>/dev/null; } ||  { error3="true"; }
    if [ "$error1" = "true" -o "$error2" = "true" -o "$error3" = "true" ]; then
        {
        printf "\n"
        if [ "$error1" = "true" ]; then printf '%s' "ERROR: Could not run \"sort --version-sort\" (necessary in order for this script to function correctly)!"; fi
        if [ "$error2" = "true" ]; then printf '%s' "ERROR: Could not run \"stat\" (necessary in order for this script to function correctly)"; fi
        if [ "$error3" = "true" ]; then printf '%s' "ERROR: Could not run \"find\" (necessary in order for this script to function correctly)"; fi
        printf "\n"
        }>/dev/stderr
        exit
    else
        sort_command="sort --version-sort"
    fi
elif [ "$OS" = "Mac" ]; then
    error1="false"
    error2="false"
    error3="false"

    { gsort --version-sort --help >/dev/null 2>/dev/null; } || { error1="true"; }
    { gstat --help >/dev/null 2>/dev/null; } ||  { error2="true"; }
    { gfind --help >/dev/null 2>/dev/null; } ||  { error3="true"; }
    if [ "$error1" = "true" -o "$error2" = "true" -o "$error3" = "true" ]; then
        {
        printf "\n"
        if [ "$error1" = "true" ]; then printf '%s' "ERROR: Could not run \"gsort --version-sort\" (necessary in order for this script to function correctly)!"; fi
        if [ "$error2" = "true" ]; then printf '%s' "ERROR: Could not run \"gstat\" (necessary in order for this script to function correctly)"; fi
        if [ "$error3" = "true" ]; then printf '%s' "ERROR: Could not run \"gfind\" (necessary in order for this script to function correctly)"; fi
        printf "\n"
        
        printf "\n"
        printf '%s\n' "You can install them by installing \"homebrew\" and then GNU \"coreutils\":"
        printf '%s\n' "sudo ruby -e \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)\""
        printf '%s\n' "sudo brew install coreutils"
        }>/dev/stderr

        exit
    else
        sort_command="gsort --version-sort"
    fi
elif [ "$OS" = "unknown" ]; then
    printf '\n%s\n\n' "ERROR: Could not get OS!">/dev/stderr
    CleanUp
    exit 1
elif [ "$OS" = "other" ]; then
    printf '\n%s\n\n' "ERROR: OS currently not supported!">/dev/stderr
    CleanUp
    exit 1
fi


#Get the program parameters into the array "params":
params_count=0
for i; do
    params_count=$((params_count+1))
    eval params_$params_count=\"\$i\"
done
params_0=$((params_count))

if [ "$params_0" = "0" ]; then #if no parameters are provided: display help
    DisplayHelp
    CleanUp && exit 0
fi


#Create a flags array. A flag denotes special parameters:
help_flag="0"
i=1;
j=0;
while [ "$i" -le "$((params_0))" ]; do
    eval params_i=\"\$\{params_$i\}\"
    case "${params_i}" in
    "--help" | "-h" )
        help_flag="1"
    ;;
    * )
        j=$((j+1))
        eval selected_params_$j=\"\$params_i\"
    ;;
    esac

    i=$((i+1))
done

selected_params_0=$j
#Rebuild params array:
DestroyArray params
for i in $(seq 1 $selected_params_0); do
    eval params_$i=\"\$\{selected_params_$i\}\"
done
params_0=$selected_params_0

if [ "$help_flag" = "1" ]; then
    DisplayHelp
else
    #Check program arguments:
    if [ "$params_0" -lt "2" ]; then
        printf '\n%s\n' "ERROR: To few program parameters provided (expected two: <dir_tree1> and <dir_tree2>)!">/dev/stderr
        exit 1
    elif [ "$params_0" -gt "2" ]; then
        printf '\n%s\n' "ERROR: To many program parameters provided (expected two: <dir_tree1> and <dir_tree2>)!">/dev/stderr
        exit 1
    else #two program arguments are provided:
        mask1="$params_1"
        mask2="$params_2"
    fi
        
    #If two program arguments are provided (<dir_tree1> and <dir_tree2>) proceed to checking them:

    initial_dir="$PWD" #Store initial dir
    error_encountered="false"

    [ -e "$params_1" -a -d "$params_1" ] && cd "$params_1" >/dev/null 2>/dev/null && {
        dir1="$PWD"
        cd "$initial_dir"
    }||{
        printf '\n%s\n' "ERROR: \"$params_1\" does not exist as a directory or is not accessible!">/dev/stderr
        error_encountered="true"
    }

    printf "\n">/dev/tty

    [ -e "$params_2" -a -d "$params_2" ] && cd "$params_2" >/dev/null 2>/dev/null && {
        dir2="$PWD"
        cd "$initial_dir"
    }||{
        printf '%s\n' "ERROR: \"$params_2\" does not exist as a directory or is not accessible!">/dev/stderr
        error_encountered="true"
    }

    if [ "$error_encountered" = "true" ]; then
        printf "\n">/dev/stderr
        exit
    fi

    GetSetRAMLocation

    #Trap "INTERRUPT" (CTRL-C) and "TERMINAL STOP" (CTRL-Z) signals:
    trap 'trap1' INT
    trap 'trap1' TSTP

    #Proceed to <dir_tree1> and <dir_tree2> compare:
    IFS="
"
    set -f
    unset count_total
    unset previous_line
    unset current_line
    unset previous_case
    skip="0"
    count="0"
    found_previous="false"
    found_previous_last_line_case="false"
    for l in $(\
        {\
            PrintJustInTitle "Loading file data, please wait...";\
            Proc2;\
            Proc3;\
            PrintJustInTitle "Sorting results, please wait...";\
        }|eval $sort_command;
    ); do
        if [ -z "$count_total" ]; then
            # #? is for removing the "." in front of the number:
            count_total=$((${l#?}))
        else
            count=$((count + 1))
            PrintJustInTitle "Analyzing file $count of $count_total"
            if [ -z "$current_line" ]; then
                #FilePath / FileType / FileSize / FileTime / SecondsSinceEpoch

                #Get previous FileType = if from <dir_tree1> or <dir_tree2>:
                previous_line_type="${l#*"///// "}"
                #extract first character from $previous_line_type ("<" or ">"):
                previous_line_type_temp="${previous_line_type#?}"
                previous_line_type="${previous_line_type%"$previous_line_type_temp"}"

                #Remove FileType from line:
                previous_line="$l"
                previous_line_file_path="${l%%" /////"*}"
                previous_line_last_part="${previous_line#*"///// ""$previous_line_type""_ ///// "}"
                previous_line="$previous_line_file_path /////$previous_line_last_part"

                previous_line_file_size="${previous_line_last_part%%" /////"*}"
                previous_line_seconds_since_epoch="${l##*" "}"

                previous_line_file_time="${previous_line#*"///// "}"
                previous_line_file_time="${previous_line_file_time%%" /////"*}"

                current_line="$previous_line"
                current_line_file_path="$previous_line_file_path"
                current_line_file_size="$previous_line_file_size"
                current_line_seconds_since_epoch="$previous_line_seconds_since_epoch"

                current_line_type="$previous_line_type"

                current_line_file_time="$previous_line_file_time"
            else
                #FilePath / FileType / FileSize / FileTime / SecondsSinceEpoch

                previous_line="$current_line"
                previous_line_file_path="$current_line_file_path"
                previous_line_file_size="$current_line_file_size"
                previous_line_seconds_since_epoch="$current_line_seconds_since_epoch"

                previous_line_type="$current_line_type"

                previous_line_file_time="$current_line_file_time"

                #Get current FileType = if from <dir_tree1> or <dir_tree2>:
                current_line_type="${l#*"///// "}"
                #extract first character from $current_line_type ("<" or ">"):
                current_line_type_temp="${current_line_type#?}"
                current_line_type="${current_line_type%"$current_line_type_temp"}"

                #Remove FileType from line:
                current_line="$l"
                current_line_file_path="${l%%" /////"*}"
                current_line_last_part="${current_line#*"///// ""$current_line_type""_ ///// "}"
                current_line="$current_line_file_path /////$current_line_last_part"

                current_line_file_size="${current_line_last_part%%" /////"*}"
                current_line_seconds_since_epoch="${l##*" "}"

                current_line_file_time="${current_line#*"///// "}"
                current_line_file_time="${current_line_file_time%%" /////"*}"

                if [ ! "$skip" = "$count"  ]; then
                    if [ "$found_previous" = "false" ]; then
                        seconds_difference=$(($current_line_seconds_since_epoch - $previous_line_seconds_since_epoch))
                        if [ \
                            \( "$current_line" = "$previous_line" \) -o \
                            \( \
                                \( "$current_line_file_path" = "$previous_line_file_path" \) -a \
                                \( "$current_line_file_size" = "$previous_line_file_size" \) -a \
                                \( "$seconds_difference" = "1" -o "$seconds_difference" = "-1" \) \
                            \) \
                        ]; then
                            found_previous="true"
                            found_previous_last_line_case="false"
                            skip=$((count+1))
                        else
                            printf '%s\n' "$previous_line_type $previous_line_file_path - ""Size: ""$previous_line_file_size"" Bytes"" - ""Modified Date: ""$previous_line_file_time"
                            found_previous="false"
                            found_previous_last_line_case="true"
                        fi
                    else
                        printf '%s\n' "$previous_line_type $previous_line_file_path - ""Size: ""$previous_line_file_size"" Bytes"" - ""Modified Date: ""$previous_line_file_time"
                        found_previous="false"
                        found_previous_last_line_case="true"
                    fi
                else
                    found_previous="false"
                    found_previous_last_line_case="true"
                fi
            fi
        fi
    done
    #Treat last case sepparatelly:
    if [ "$found_previous_last_line_case" = "true" ]; then
        printf '%s\n' "$current_line_type $current_line_file_path - ""Size: ""$current_line_file_size"" Bytes"" - ""Modified Date: ""$current_line_file_time"
    fi

    unset IFS
    set +f
fi

CleanUp
  • Как использовать:

    Синтаксис:<caller_shell> '/path/to/diffm.sh' <dir_tree1> <dir_tree2>

     где:<caller_shell>может быть любой оболочкой :dash, bash, zshили любой другой оболочкой, совместимой с синтаксисом оболочки dash.

  • Что он делает :Сравнивает файлы (рекурсивно )в двух предоставленных путях дерева каталогов(<dir_tree1>и<dir_tree2>)по:

    1. Путь
    2. Размер
    3. Дата модификации

Примечания:

  • Этот сценарий сравнивает только файлы, а не каталоги в <dir_tree1>и <dir_tree2>.

  • Чтобы узнать, как использовать скрипт, вы можете вызвать его с флагом --help.

1
28.11.2020, 15:48

Midnight Commander (mc в Debian linux )— это файловый менеджер с двумя -панелями -с функцией сравнения каталогов (C -x d; то есть, удерживая клавишу управления, нажмите x, отпустите, затем нажмите d ). У него есть три варианта :«Быстрый», «Только размер» и «Тщательный». Quick или Size only могут быть вам полезны. Затем он выделяет файлы, которые различаются на обеих панелях, поэтому вы можете что-то сделать с одним или обоими наборами.

Я использую описанный выше метод rsync, когда у меня много файлов и ясный исходный и целевой каталоги. Но я часто обнаруживаю, что у меня есть два каталога, в каждом из которых есть новые файлы для синхронизации, и в итоге я часто использую mc.

0
02.12.2020, 22:08

Я только что обнаружил tree.

tree old_dir/ > tree_old
tree new_dir/ > tree_new
vimdiff tree_old tree_new
3
18.12.2020, 07:45

Если вы открыты для решения на основе графического интерфейса -,meldтакже может выполнять сравнение каталогов.

0
18.12.2020, 08:31

Теги

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