Script para comparar dois parâmetros de entrada e mostrar letra (s) compartilhada (s)

4

Estou escrevendo um script que quero que um usuário insira duas palavras separadas e o resultado para mostrar qual letra as duas palavras compartilham. Por exemplo ./share Cat Rat - retornaria letras compartilhadas: "a" e "t". Meu pensamento foi ler $ 1 e $ 2 em um loop, mas depois disso, eu não tenho certeza para onde ir. Eu estou apenas começando a aprender scripting e unix, então qualquer ajuda é apreciada!

#!/bin/sh

echo "$1"|while read line
    
por swam 01.10.2014 / 22:31

3 respostas

5

Se você puder confiar nas expressões regulares internas do Bash (ou seja, no operador =~ ) e nas variáveis do array, você pode usar algo assim:

#!/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"

A primeira linha cria uma matriz que contém todos os caracteres contidos em $1 . Em seguida, $2 é salvo e, em seguida, os parâmetros posicionais são definidos para os valores de $W1 elements. Então, cada caractere (agora parâmetro posicional) é comparado com a segunda palavra salva e, se a correspondência for encontrada, será impressa. Por último, os parâmetros posicionais são deslocados para que o loop continue com o próximo caractere.

Conceitos que você pode ver aqui: trabalhando com uma matriz, capturando a saída de um comando em uma variável, alterando argumentos posicionais, loop e instruções condicionais.

Se você quiser fazê-lo simplesmente, você pode querer considerar, por exemplo, este (na verdade, é uma divisão de uma linha para maior legibilidade):

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

Os combos sed | sort -u apenas dividem as palavras em um único caractere por formulários de linha. grep -F trata o parâmetro (aqui a segunda palavra dividida) como sequências fixas que devem ser correspondidas na entrada e, portanto, tenta corresponder a cada caractere em $1 com cada caractere em $2 . Em situações reais, você provavelmente removeria a segunda combinação de sort | uniq , já que "palavras" geralmente são curtas e qualquer ganho de desempenho seria eliminado pela geração de dois processos adicionais. No entanto, como $2 fica maior (centenas ou milhares de linhas), você definitivamente quer fazer qualquer otimização possível.

Você também pode substituir o comando sed por fold -w 1 , que faz quase o mesmo (é mais curto para digitar, mas o comando sed s é o canivete suíço de processamento de texto).

    
por 01.10.2014 / 22:58
4

a seguir é uma abordagem simples que percorre a primeira string e verifica se cada caractere está presente na segunda string; se o caractere estiver presente, ele imprimirá isso no console.

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

Se você gosta de pequenas frases de efeito e está certo em usar ferramentas comuns do GNU coreutils, então você pode fazer algo assim:

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

Se você não se importa com o caso das letras, pode alternar $1 e $2 com ${1,,} e ${2,,} respectivamente.

Além do comm , fold e sort , isso usa <( ) substituições do comando e <<< aqui-strings .

Como alternativa, se você quiser uma resposta pura (sem coreutils) e quiser mais exposição a vários recursos do bash, aqui está outra:

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

Isso usa uma matriz associativa bash, portanto, requer a versão 4 ou superior. / p>

Ele também usa (( )) expansões aritméticas com aritmética bitwise.

Funciona através dos caracteres da primeira string e usa cada um deles como um índice no array associativo. O elemento correspondente a esse índice é ORed com 1 (ou tem seu bit 0 definido).

O mesmo é feito para a segunda string, exceto que o elemento é ORed com 2 (ou tem seu conjunto de bits 1).

Em seguida, percorremos o array procurando por elementos com bits 0 e 1 configurados (ou seja, igual a 3) e emitindo o índice (que é uma letra comum).

    
por 02.10.2014 / 01:48