2 つの文字列変数を比較し、両方で同じ文字を出力したいと考えています。comm
これを行う方法がよくわかりません。 orを使用することを考えてdiff
いましたが、一致する文字のみを出力するための正しいパラメーターがよくわかりません。また、ファイルを取り込むと言い、これらは文字列です。誰でも助けることができますか?
入力:
a=$(echo "abghrsy")
b=$(echo "cgmnorstuvz")
出力:
"grs"
2 つの文字列変数を比較し、両方で同じ文字を出力したいと考えています。comm
これを行う方法がよくわかりません。 orを使用することを考えてdiff
いましたが、一致する文字のみを出力するための正しいパラメーターがよくわかりません。また、ファイルを取り込むと言い、これらは文字列です。誰でも助けることができますか?
入力:
a=$(echo "abghrsy")
b=$(echo "cgmnorstuvz")
出力:
"grs"
$a
変数を割り当ててシェルするためにそれほど多くの作業を行う必要はありません$b
。ただ...
a=abghrsy
b=cdgmrstuvz
さて、最長共通サブシーケンス1と呼ばれる古典的なコンピュータ サイエンスの問題があり、これはあなたの問題に似ています。
ただし、一般的な文字だけが必要な場合は、Ruby に作業を任せる方法があります...
$ ruby -e "puts ('$a'.chars.to_a & '$b'.chars.to_a).join"
1. 別の最長共通部分文字列問題と混同しないでください。
gnu coreutils を使用 (@DigitalRoss に触発)。
a="abghrsy"
b="cgmnorstuvz"
echo "$(comm -12 <(echo "$a" | fold -w1 | sort | uniq) <(echo "$b" | fold -w1 | sort | uniq) | tr -d '\n')"
印刷されますgrs
。ユニークな文字だけが必要だと思いました。
更新: ダッシュ用に変更..
#!/bin/dash
string1=$(printf "$1" | fold -w1 | sort | uniq | tr -d '\n');
string2=$(printf "$2" | fold -w1 | sort | uniq | tr -d '\n');
while [ "$string1" != "" ]; do
c1=$(printf '%s\n' "$string1" | cut -c 1-1 )
string2=$(printf "$2" | fold -w1 | sort | uniq | tr -d '\n');
while [ "$string2" != "" ]; do
c2=$(printf '%s\n' "$string2" | cut -c 1-1 )
if [ "$c1" = "$c2" ]; then
echo "$c1\c"
fi
string2=$(printf '%s\n' "$string2" | cut -c 2- )
done
string1=$(printf '%s\n' "$string1" | cut -c 2- )
done
echo;
注:私は初心者です。これを行うためのより良い方法があるかもしれません。
良い質問+1。
awk トリックを使用してこれを行うことができます。
a=abghrsy
b=cdgmrstuvz
comm -12 <(echo $a|awk -F"\0" '{for (i=1; i<=NF; i++) print $i}') <(echo $b|awk -F"\0" '{for (i=1; i<=NF; i++) print $i}')|tr -d '\n'
出力:
grs
これを使用するとawk -F"\0"
、入力文字列が 1 文字ずつ異なる awk フィールドに分割されることに注意してください。Rest は、 と を非常に簡単に使用comm
しtr
ます。
PS:入力文字列がソートされていない場合は、awk の出力をパイプしてソートするか、awk 内で配列のソートを行う必要があります。
echo "$a;$b" | awk -F"\0" '{scnd=0; for (i=1; i<=NF; i++) {if ($i!=";") {if (!scnd) arr1[$i]=$i; else if ($i in arr1) arr2[$i]=$i} else scnd=1}} END { for (a in arr2) printf("%s", a)}'
これは、文字列にセミコロンが含まれていないことを前提としています (そうでない場合は、他の文字を使用できます)。
(@CodeGnomeからの回答に感謝)
echo "$b" | grep -o "[$a]" | tr -d '\n'
これは広く適用できるソリューションではありませんが、特定のユース ケースには非常に適しています。アイデアは、最初の変数を文字クラスとして使用して、2 番目の文字列と照合することです。例えば:
a='abghrsy'
b='cgmnorstuvz'
echo "$b" | grep --only-matching "[$a]" | xargs | tr --delete ' '
これはgrs
期待どおりに生成されます。xargsとtrの使用は、出力から改行とスペースを削除するだけであることに注意してください。必要に応じて、これを別の方法で処理することもできます。
ただし、本当に探しているのは、設定された交差点です。シェルで「ウィング」することもできますが、Ruby、Python、Perl などの言語を使用した方がよいでしょう。
既存のシェル スクリプトと統合する必要がある場合は、現在のスクリプト内で Bash 変数を使用するシンプルな Ruby ワンライナーを次のように呼び出すことができます。
a='abghrsy'
b='cgmnorstuvz'
ruby -e "puts ('$a'.split(//) & '$b'.split(//)).join"
代わりにすべてを Ruby で行うことで、確かに物事をよりエレガントにすることができます。
string1_chars = 'abghrsy'.split //
string2_chars = 'cgmnorstuvz'.split //
intersection = string1_chars & string2_chars
puts intersection.join
これは確かに私には読みやすく堅牢に思えますが、あなたのマイレージは異なる場合があります. 少なくとも今は、選択できるオプションがいくつかあります。