用于比较 2 个输入参数并显示共享字母的脚本

用于比较 2 个输入参数并显示共享字母的脚本

我正在编写一个脚本,希望用户输入两个单独的单词,结果显示这两个单词共享哪个字母。例如 ./share Cat Rat - 将返回共享字母:“a”和“t”。我的想法是循环读取 $1 和 $2,但在那之后,我不太确定该去哪里。我刚刚开始学习脚本和 UNIX,所以非常感谢您的帮助!

#!/bin/sh

echo "$1"|while read line

答案1

如果您可以依赖 Bash 内置正则表达式(即=~运算符)和数组变量,您可以使用如下内容:

#!/bin/bash
W1=( $( echo "$1" | sed "s/./\n&/g" | sort -u ) )
W2="$2"
set ${W1[*]}

while [[ ! -z "$1" ]]; do
    if [[ "$W2" =~ "$1" ]]; then
        printf "$1 "
    fi
    shift
done
printf "\n"

第一行创建一个数组,其中包含 中包含的每个字符$1。接下来,$2保存,然后将位置参数设置为$W1元素的值。然后每个字符(现在是位置参数)与保存的第二个单词进行匹配,如果找到匹配,则将其打印出来。最后,位置参数被移动,以便循环继续处理下一个字符。

您可以在此处看到的概念:使用数组、将命令的输出捕获到变量中、更改位置参数、循环和条件语句。

如果你想简单地做到这一点,你可能需要考虑例如这个(实际上它是单行拆分以增加可读性):

#!/bin/bash
printf "$1" \
    | sed "s/./\n&/g" | sort -u \
    | grep -F "$( printf "$2" | sed 's/./&\n/g' | sort -u )"

这些sed | sort -u组合只是将单词分成每行形式一个唯一的字符。grep -F将参数(这里是分秒词)视为要在输入中匹配的固定字符串,因此它尝试将 中的每个字符$1与 中的每个字符进行匹配$2。在实际情况下,您可能会删除第二个sort | uniq组合,因为“单词”通常相当短,并且任何性能增益都会因产生两个额外的进程而被杀死。然而,随着$2变得更大(数百或数千行),您肯定想要进行任何可能的优化。

你也可以用sedwhich替换命令fold -w 1,其作用几乎相同(它的打字时间更短,但sed它的s命令是文本处理的瑞士军刀)。

答案2

以下是一种简单的方法,它迭代第一个字符串并检查第二个字符串中是否存在每个字符,如果存在该字符,它将在控制台上打印该字符。

str1=$1;
i=0
while [ $i -ne ${#str1} ]
 do
 c=${str1:$i:1}
 if [[ $2 == *$c* ]]
  then
   echo $c
 fi
 ((i++))
done

答案3

如果您喜欢时髦的小俏皮话,并且可以使用 GNU coreutils 中的常用工具,那么您可以执行以下操作:

comm -12 <( fold -w1 <<< "$1" | sort -u ) <( fold -w1 <<< "$2" | sort -u )

如果你不关心字母的大小写,可以分别将$1and$2${1,,}and进行切换${2,,}

以及comm,foldsort实用程序,这使用<( ) 命令替换<<< 这里的字符串


或者,如果您想要一个纯粹的 bash 答案(无 coreutils)并希望更多地了解各种 bash 功能,这里还有另一个:

declare -A arr
for (( i=0; i<${#1}; i++ )); do
    (( arr[${1:i:1}] |= 1 ))
done
for (( i=0; i<${#2}; i++ )); do
    (( arr[${2:i:1}] |= 2 ))
done
for i in ${!arr[@]}; do
    if (( ${arr[$i]} == 3 )); then
        echo $i
    fi
done

这使用了 bash关联数组,因此需要版本 4 或更高版本。

它还使用(( )) 算术展开式与按位算术。

它遍历第一个字符串的字符,并将每个字符用作关联数组的索引。与该索引对应的元素与 1 进行或运算(或将其位 0 置位)。

对第二个字符串执行相同的操作,只不过该元素与 2 进行“或”运算(或设置了其位 1)。

然后我们遍历数组寻找设置了位 0 和 1(即等于 3)的元素并输出索引(这是一个常见的字母)。

相关内容