diff(-q)가 파일 내용을 확인하지 않고 크기와 mtime만 확인하도록 하는 옵션이 있습니까? 그렇지 않은 경우 이 옵션을 제공하는 유사한 도구가 있습니까?
답변1
를 사용 rsync
하되 파일을 복사하거나 삭제하지 않도록 지시합니다.
rsync -a -nv --delete a/ b/
답변2
다음 스크립트는 답변을 개선한 것입니다.여기:
#!/bin/sh
# 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
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
}
DetectShell () {
eval $1=\"\";
if [ -n "$BASH_VERSION" ]; then
eval $1=\"bash\";
elif [ -n "$ZSH_VERSION" ]; then
eval $1=\"zsh\";
elif [ "$PS1" = '$ ' ]; then
eval $1=\"dash\";
else
eval $1=\"undetermined\";
fi
}
PrintInTitle () {
printf "\033]0;%s\007" "$1"
}
PrintJustInTitle () {
PrintInTitle "$1">/dev/tty
}
trap1 () {
CleanUp
printf "\nAborted.\n">/dev/tty
}
CleanUp () {
#Restore "INTERRUPT" (CTRL-C) and "TERMINAL STOP" (CTRL-Z) signals:
trap - INT
trap - TSTP
#Restore Initial Directory:
cd "$initial_dir"
#Clear the title:
PrintJustInTitle ""
#Restore initial IFS:
#IFS=$old_IFS
unset IFS
#Set shell flags (enable globbing):
set +f
}
DisplayHelp () {
printf "\n"
printf "diffm - DIFF by Modification date\n"
printf "\n"
printf " What it does:\n"
printf " - compares the files 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 the files in the two provided directory tree paths are compared, not also the folders\n"
printf "\n"
}
Proc1 () {
{\
{\
cd "$initial_dir"
[ -n "$dir1" ] && { cd "$dir1"; PrintJustInTitle "Loading files in directory 1, please wait..."; }
eval $command1
cd "$initial_dir"
[ -n "$dir2" ] && { cd "$dir2"; PrintJustInTitle "Loading files in directory 2, please wait..."; }
eval $command2
cd "$initial_dir"
}|eval $sort_command;
}|eval $uniq_command;
}
Proc2 () {
cd "$initial_dir"
[ -n "$dir1" ] && { cd "$dir1"; PrintJustInTitle "Loading files in directory 1, please wait..."; }
eval $command1
cd "$initial_dir"
[ -n "$dir2" ] && { cd "$dir2"; PrintJustInTitle "Loading files in directory 2, please wait..."; }
eval $command2
cd "$initial_dir"
}
GetOS OS
DetectShell current_shell
OS_CASE=""
if [ "$OS" = "Linux" ]; then
OS_CASE="1"; # = use Linux OS commands
elif [ "$OS" = "Mac" ]; then
OS_CASE="2"; # = use Mac OS commands
else
#################################################################################
## IN CASE YOUR OS IS NOT LINUX OR MAC: ##
## MODIFY THE NEXT VARIABLE ACCORDING TO YOUR SYSTEM REQUIREMENTS (e.g.: ##
## "1" (use Linux OS commands) or "2" (use Mac OS commands)): ##
#################################################################################
OS_CASE="3"
fi
if [ "$current_shell" = "undetermined" ]; then
printf "\nWarning: This script was designed to work with dash, bash and zsh shells.\n\n">/dev/tty
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:
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 #Run program:
error1="false"
error2="false"
error3="false"
error4="false"
{ 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"; }
{ uniq --help >/dev/null 2>/dev/null; } || { error4="true"; }
if [ "$error1" = "true" -o "$error2" = "true" -o "$error3" = "true" -o "$error4" = "true" ]; then
{
printf "\n"
if [ "$error1" = "true" ]; then printf '%s' "ERROR: Could not run \"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
if [ "$error4" = "true" ]; then printf '%s' "ERROR: Could not run \"uniq\" (necessary in order for this script to function correctly)!"; fi
printf "\n"
}>/dev/stderr
exit
fi
#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
fi
initial_dir="$PWD" #Store initial dir
#If two program arguments are provided (<dir_tree1> and <dir_tree2>) proceed to checking them:
initial_dir="$PWD" #Store initial dir
dir1=""
dir2=""
file1=""
file2=""
error_encountered="false"
error1="false"
error2="false"
[ -e "$params_1" ] && {
if [ -d "$params_1" ]; then
cd "$params_1" >/dev/null 2>/dev/null && {
dir1="$PWD"
cd "$initial_dir"
} || {
error1="true"
}
elif [ ! -d "$params_1" ]; then
file1="$params_1"
fi
}||{
error2="true"
}
if [ "$error1" = "true" -o "$error2" = "true" ]; then
printf '\n%s\n' "ERROR: PARAMETER1: \"$params_1\" does not exist as a directory/file or is not accessible!">/dev/stderr
error_encountered="true"
fi
printf "\n">/dev/tty
error1="false"
error2="false"
[ -e "$params_2" ] && {
if [ -d "$params_2" ]; then
cd "$params_2" >/dev/null 2>/dev/null && {
dir2="$PWD"
cd "$initial_dir"
}||{
error1="true"
}
elif [ ! -d "$params_2" ]; then
file2="$params_2"
fi
}||{
error2="true"
}
if [ "$error1" = "true" -o "$error2" = "true" ]; then
printf '%s\n' "ERROR: PARAMETER2: \"$params_2\" does not exist as a directory/file or is not accessible!">/dev/stderr
error_encountered="true"
fi
if [ "$error_encountered" = "true" ]; then
printf "\n">/dev/stderr
exit
fi
## TYPE ///// PATH ///// SIZE ///// LAST TIME WRITE IN SECONDS ##
if [ "$OS_CASE" = "1" ]; then #Linux OS
if [ -n "$dir1" ]; then
command1='find . -not -type d -exec stat -c "< ///// %n ///// %s ///// %Y" {} \;'
else
command1_string="$(stat -c "< ///// %n ///// %s ///// %Y" "$file1")"
command1="printf '%s\n' \"\$command1_string\""
fi
if [ -n "$dir2" ]; then
command2='find . -not -type d -exec stat -c "> ///// %n ///// %s ///// %Y" {} \;'
else
command2_string="$(stat -c "> ///// %n ///// %s ///// %Y" "$file2")"
command2="printf '%s\n' \"\$command2_string\""
fi
command3='date -d @'
cd "$initial_dir"
sort_command="sort -k 3"
uniq_command="uniq -u -f 2"
elif [ "$OS_CASE" = "2" ]; then #Mac OS
if [ -n "$dir1" ]; then
command1='find . -not -type d -exec stat -f "< ///// %N ///// %z ///// %m" {} \;'
else
command1_string="$(stat -f "< ///// %N ///// %z ///// %m" "$file1")"
command1="printf '%s\n' \"\$command1_string\""
fi
if [ -n "$dir2" ]; then
command2='find . -not -type d -exec stat -f "> ///// %N ///// %z ///// %m" {} \;'
else
command2_string="$(stat -f "> ///// %N ///// %z ///// %m" "$file2")"
command2="printf '%s\n' \"\$command2_string\""
fi
command3='date -j -f %s '
cd "$initial_dir"
sort_command="sort -k 3"
uniq_command="uniq -u -f 2"
else
printf '\n%s\n\n' "Error: Unsupported OS!">/dev/stderr
exit 1
fi
#Trap "INTERRUPT" (CTRL-C) and "TERMINAL STOP" (CTRL-Z) signals:
trap 'trap1' INT
trap 'trap1' TSTP
old_IFS="$IFS" #Store initial IFS value
IFS="
"
set -f #Set shell flags (disable globbing):
found_previous="false"
count=0
skip=0
if [ -n "$dir1" -o -n "$dir2" ]; then
for line in $(\
if [ -n "$dir1" -a -n "$dir2" ]; then\
Proc1;\
elif [ -z "$dir1" -o -z "$dir2" ]; then\
Proc2;\
fi;\
); do
count=$((count+1))
PrintJustInTitle "Analyzing file $count..."
if [ -z "$current_line_file_type" ]; then
current_line="$line"
current_line_file_type="${line%%" ///// "*}"
current_line_file_mtime_in_seconds="${line##*" ///// "}"
current_line_file_type_path_and_size="${line%" ///// "*}"
current_line_file_size="${current_line_file_type_path_and_size##*" ///// "}"
current_line_file_type_path="${line%" ///// "*" ///// "*}"
current_line_file_path="${current_line_file_type_path#*" ///// "}"
else
previous_line="$current_line"
previous_line_file_type="$current_line_file_type"
previous_line_file_mtime_in_seconds="$current_line_file_mtime_in_seconds"
previous_line_file_type_path_and_size="$current_line_file_type_path_and_size"
previous_line_file_size="$current_line_file_size"
previous_line_file_type_path="$current_line_file_size"
previous_line_file_path="$current_line_file_path"
current_line="$line"
current_line_file_type="${line%%" ///// "*}"
current_line_file_mtime_in_seconds="${line##*" ///// "}"
current_line_file_type_path_and_size="${line%" ///// "*}"
current_line_file_size="${current_line_file_type_path_and_size##*" ///// "}"
current_line_file_type_path="${line%" ///// "*" ///// "*}"
current_line_file_path="${current_line_file_type_path#*" ///// "}"
if [ ! "$skip" = "$count" ]; then
if [ "$found_previous" = "false" ]; then
seconds_difference=$(($current_line_file_mtime_in_seconds - $previous_line_file_mtime_in_seconds))
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"
skip=$((count+1))
else
printf '%s\n' "$previous_line_file_type $previous_line_file_path - ""Size: ""$previous_line_file_size"" Bytes"" - ""Modified Date: ""$(eval $command3$previous_line_file_mtime_in_seconds)"
found_previous="false"
fi
else
printf '%s\n' "$previous_line_file_type $previous_line_file_path - ""Size: ""$previous_line_file_size"" Bytes"" - ""Modified Date: ""$(eval $command3$previous_line_file_mtime_in_seconds)"
found_previous="false"
fi
else
found_previous="false"
fi
fi
done
#Treat last case separately:
if [ "$count" -gt "0" ]; then
if [ "$found_previous" = "false" ]; then
printf '%s\n' "$current_line_file_type $current_line_file_path - ""Size: ""$current_line_file_size"" Bytes"" - ""Modified Date: ""$(eval $command3$current_line_file_mtime_in_seconds)"
fi
fi
else
line1=""
line2=""
for line in $(\
if [ -n "$dir1" -a -n "$dir2" ]; then\
Proc1;\
elif [ -z "$dir1" -o -z "$dir2" ]; then\
Proc2;\
fi;\
); do
if [ -z "$line1" ]; then
line1="$line"
line1_file_type="${line%%" ///// "*}"
line1_file_mtime_in_seconds="${line##*" ///// "}"
line1_file_type_path_and_size="${line%" ///// "*}"
line1_file_size="${line1_file_type_path_and_size##*" ///// "}"
line1_file_type_path="${line%" ///// "*" ///// "*}"
line1_file_path="${line1_file_type_path#*" ///// "}"
else
line2="$line"
line2_file_type="${line%%" ///// "*}"
line2_file_mtime_in_seconds="${line##*" ///// "}"
line2_file_type_path_and_size="${line%" ///// "*}"
line2_file_size="${line2_file_type_path_and_size##*" ///// "}"
line2_file_type_path="${line%" ///// "*" ///// "*}"
line2_file_path="${line2_file_type_path#*" ///// "}"
seconds_difference=$(($line2_file_mtime_in_seconds - $line1_file_mtime_in_seconds))
if [ \
\( "$line2_file_size" = "$line1_file_size" \) -a \
\( \
\( "$line2_file_mtime_in_seconds" = "$line1_file_mtime_in_seconds" \) -o \
\( "$seconds_difference" = "1" -o "$seconds_difference" = "-1" \) \
\) \
]; then
:;
else
printf '%s\n' "$line1_file_type $line1_file_path - ""Size: ""$line1_file_size"" Bytes"" - ""Modified Date: ""$(eval $command3$line1_file_mtime_in_seconds)"
printf '%s\n' "$line2_file_type $line2_file_path - ""Size: ""$line2_file_size"" Bytes"" - ""Modified Date: ""$(eval $command3$line2_file_mtime_in_seconds)"
fi
fi
done
fi
CleanUp
fi
- 할 수 있는 작업:
- 인수로 제공된 두 디렉터리 트리 경로의 파일을 (재귀적으로) 다음과 같이 비교합니다(우리는 이를 :
<dir_tree1>
및 로 표시함<dir_tree2>
).- 상대 경로
- 크기
- 수정일
- 차이점이 발견된 경우: 다양한 파일의 상대 경로와 세부 정보(크기 및 수정 날짜)가 나열됩니다.
- 파일의 상대 파일 경로에는 ' '
<dir_tree1>
접두사가 붙습니다 .<
- 파일의 상대 파일 경로에는 ' '
<dir_tree2>
접두사가 붙습니다 .>
- 파일의 상대 파일 경로에는 ' '
- 노트:
- 디렉터리가 아닌 파일만 비교
- Linux OS, Mac OS에서 실행되어야 하며 추가 도구를 설치할 필요가 없습니다.
답변3
아니요 diff
- 이를 위해 파일을 찾을 필요는 없습니다. stat
해당 정보를 다음과 같이 셸에 있는 정보와 비교하면 됩니다.
if [[ $(stat -c%s_%Y file1) == $(stat -c%s_%Y file2) ]]
then echo equal
else echo different
fi
이 stat
명령은 파일 inode의 정보를 제공하므로 상황 에 따라 -c
원하는 속성을 선택할 수 있습니다 .%s
%Y