0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

シェルスクリプトを用いて複数のxmlどうしを比較し差分を発見する

Last updated at Posted at 2025-08-25

ことの経緯

とある業務において、MW上にxmlを用いて設定値をインポートしていた。

MW上で設定値変更も可能で、修正依頼が来るたびに修正したxmlをMWに設定しなければならない。そのため、MWの設定値とこちらで管理しているxmlとの間でずれが生じてしまう場合がたまにあった。

そこで、現在のMWに設定されている値と、こちらで管理しているxmlの値に相違がないかを把握しておきたかった。MWの設定値はxmlファイルとしてexport可能なため、お互いのxmlを比較して違いを発見するスクリプトを作成したい。

差分比較スクリプト

compared_xml.sh
# 二つのディレクトリ内にある同名のxmlファイルを比較して差分を表示する
# 一方にのみ存在するファイルまたはxml以外のファイルは比較対象外とする
# -------------------------------------------

# 事前にディレクトリの作成が必要(MASTER_DIR、DIR1、DIR2)
readonly MASTER_DIR=/tmp/compare_xml2
# 各ディレクトリ以下にxmlを配置する
readonly DIR1="${MASTER_DIR}/org/"
readonly DIR2="${MASTER_DIR}/new/"

timestamp=$(date +"%Y%m%d_%H%M%S")
readonly DIFF_LOG="${MASTER_DIR}/diff_files_${timestamp}.log"

file_sum=0
diff_files=()
# DIR1に存在しないファイル一覧
not_exist_dir1=()
# DIR2に存在しないファイル一覧
not_exist_dir2=()

# -------------------------------------------

# ログにのみ出力
function logger() {
    echo "$1" >> $DIFF_LOG
}

# 画面とログ両方に出力
function func_tee() {
    echo "$1" | tee -a $DIFF_LOG
}

# 引数で受け取った配列を画面とログに出力
function print_and_log_array() {

    num_count=0
    declare -n files=$1
    if [ ${#files[@]} -eq 0 ]; then
        func_tee "特になし"
    else
        for file in "${files[@]}"
        do
            num_count=`expr $num_count + 1`
            func_tee "$num_count.$file"
        done
    fi
}
# -------------------------------------------

if [ ! -d "$DIR1" ] || [ ! -d "$DIR2" ]; then
    echo "どちらかのディレクトリが存在しません。"
    exit 1
fi

# DIR1とDIR2内にあるxmlファイルの重複を排除したファイル一覧
xml_files=$(( ls "$DIR1"/*.xml 2>/dev/null; ls "$DIR2"/*.xml 2>/dev/null ) | rev | cut -d"/" -f1 | rev | sort -u)

for xml_file in $xml_files; do
    # 二つのディレクトリのフルバス
    file_path1="$DIR1/$xml_file"
    file_path2="$DIR2/$xml_file"

    # 両ディレクトリに存在する
    if [[ -f "$file_path1" && -f "$file_path2" ]]; then
        if ! diff -q "$file_path1" "$file_path2" > /dev/null; then
            logger " ============== ファイル名:$xml_file =============="
            logger "diff $file_path1 $file_path2"
            diff_output=$(diff --suppress-common-lines "$file_path1" "$file_path2")
            logger "$diff_output"
            logger ""
            logger "----------------------------------------------------"
            logger ""
            # 差分ありのファイルを配列に追加
            diff_files+=("$xml_file")
        fi
        file_sum=`expr $file_sum + 1`
    # DIR2に存在しないファイル
    elif [[ -f "$file_path1" ]]; then
        not_exist_dir2+=("$xml_file")
    # DIR1に存在しないファイル
    elif [[ -f "$file_path2" ]]; then
        not_exist_dir1+=("$xml_file")
    fi
done

func_tee ""
func_tee " ============== 差分ありファイル一覧 =============="
func_tee ""
print_and_log_array diff_files

func_tee ""
func_tee "差分ファイル総数: ${#diff_files[@]}"
func_tee "比較ファイル総数: ${file_sum} (一方にのみ存在するファイルは含めず)"

func_tee ""
func_tee " ==============「${DIR2}」にのみ存在するファイル =============="
print_and_log_array not_exist_dir1

func_tee ""
func_tee " ==============「${DIR1}」にのみ存在するファイル =============="
print_and_log_array not_exist_dir2
func_tee ""

exit 0

終わりに

ターミナルとログどちらにも出力したかったので上記の実装にした。
このスクリプトで分かるのは同名ファイルの中身に違いがあるかどうか
2000ファイル近くの設定(xmlファイル)があるためスクリプト化したかった。
awkを使いこなせたらもっと端的に記述できたと思う。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?