我正在编写一个脚本,希望用户输入两个单独的单词,结果显示这两个单词共享哪个字母。例如 ./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
变得更大(数百或数千行),您肯定想要进行任何可能的优化。
你也可以用sed
which替换命令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 )
如果你不关心字母的大小写,可以分别将$1
and$2
与${1,,}
and进行切换${2,,}
。
以及comm
,fold
和sort
实用程序,这使用<( )
命令替换和<<<
这里的字符串。
或者,如果您想要一个纯粹的 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)的元素并输出索引(这是一个常见的字母)。