【问题标题】:Compare a list of strings in Bash比较 Bash 中的字符串列表
【发布时间】:2021-10-29 18:28:09
【问题描述】:

我在一个名为 rpmlist.txt 的文件中有一个 rpm 文件列表,我必须将其与另一个列表 newlist.txt 进行比较,看看它们在 Bash 中是否相同。例如,这是我的要求:

rpmlist.txt 中的文件

bash-4.4-9.10.1_x86_64
binutils-2.32-7.8.1_x86_64
bison-3.0.4-1.268_x86_64

newlist.txt 中的文件

bash-5.4-9.10.1_x86_64
binutils-2.32-7.8.1_x86_64
bison-6.0.4-1.268_x86_64

并打印它们是否匹配。任何帮助将不胜感激

【问题讨论】:

  • diff -y file1 file2, comm -12 <(sort file1) <(sort file2), grep -f file1 file2 ...
  • 行的顺序重要吗?
  • 不,订单可以是任何东西。只需 list1 必须检查 list2 上是否有任何匹配项。
  • 什么是list2? newlist.txt 可以包含不在 rpmlist.txt 中的文件吗? rpmlist.txt 可以包含不在 newlist.txt 中的文件吗?
  • 您使用“相等”等词的方式是模棱两可的。如果您在问题中添加“匹配”和“不匹配”的示例,将会有所帮助。 1:abc = 2:abc ? 1:abc = 2:acb ? 1:abc = 2:abcd ? 1:abc = 2:bcd ? 1:abc = 2:ab ?等

标签: linux bash shell


【解决方案1】:

尝试:

#!/bin/bash

# Load files into arrays

readarray source_list < rpmlist.txt
readarray target_list < newlist.txt

# Check files size

source_size=${#source_list[@]}
target_size=${#target_list[@]}

if [ ${source_size} -ne ${target_size} ]; then
    echo "File lines count not matching!" >&2
    exit 1
fi

# Enum files

for (( i=0; i < ${source_size}; i++ )); do

  # Get file name

  source_file=${source_list[$i]}
  target_file=${target_list[$i]}

  # Remove CR/LF

  source_file=$(echo "${source_file}" | sed 's:\r$::')
  target_file=$(echo "${target_file}" | sed 's:\r$::')

  # Check if files exist

  if [ ! -f ${source_file} ] || [ ! -f ${target_file} ]; then
    echo "Source and/or Target does not exist." >&2
    exit 2
  fi

  # Compare files

  diff -q "${source_file}" "${target_file}"

done 

PS:我测试过了,它可以工作。

编辑 (1)

基于cmets,我认为你应该用以下简单命令替换我的脚本:

cat rpmlist.txt | xargs -I "{}" grep "{}" newlist.txt

编辑 (2) - 不匹配列表

cat rpmlist.txt | xargs -I "{}" grep -v "{}" newlist.txt

【讨论】:

  • 我收到一个错误 -> 文件行数不匹配!
  • 计数会有所不同@Antonio
  • 如你所见,它检查源文件中的行数必须与目标文件的文件数匹配。请检查并删除所有空白行。
  • 源文件行数总是较少。我们无法预测,因为它是来自操作系统的包列表。
  • 好的,但是您没有在帖子中解释这一点。所以我没有猜到这个细节。
【解决方案2】:

这将交叉比较任意数量的此类文件。

#!/bin/bash
set -e

declare -ar list_names=("$@")
declare -Ai "${list_names[@]}"

for list in "${list_names[@]}"; do
  declare -n set="$list"
  while IFS= read -r line; do
    ((++set["$line"]))
  done < "${list}.txt"
done

compare_lists() {
  local -rn set1="$1"
  local -rn set2="$2"
  local name
  echo "Lines in ${1}, but not in ${2}:"
  for name in "${!set1[@]}"; do
    ((set2["${name}"])) || printf '  %s\n' "$name"
  done
}

declare -i idx jdx
for ((idx = 0; idx < ${#list_names[@]}; ++idx)); do
  for ((jdx = idx + 1; jdx < ${#list_names[@]}; ++jdx)); do
    compare_lists "${list_names[idx]}" "${list_names[jdx]}"
    compare_lists "${list_names[jdx]}" "${list_names[idx]}"
  done
done

示例(当上述脚本调用listdiff.sh时):

$ ./listdiff.sh rpmlist newlist
Lines in rpmlist, but not in newlist:
  bison-3.0.4-1.268_x86_64
  bash-4.4-9.10.1_x86_64
Lines in newlist, but not in rpmlist:
  bison-6.0.4-1.268_x86_64
  bash-5.4-9.10.1_x86_64

它可以得到比 2 更多的参数。

【讨论】:

  • 出现错误:./bash.sh rpmlist newlist ./bash.sh:第 7 行:rpmlist.txt:没有这样的文件或目录 ./bash.sh:第 7 行:newlist.txt: No such file or directory Lines in rpmlist, but not in newlist: Lines in newlist, but not in rpmlist:
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-30
  • 2012-03-02
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 2015-12-07
  • 1970-01-01
相关资源
最近更新 更多