次の簡単なスクリプトがあります。
- 電子メールが特定のパターンと一致することを確認する
- その場合は、タグリストにタグを追加してください。
- 終了する前にタグリストを印刷してください。
set -e
lista_tag=()
in_file="/tmp/grepmail-classify.txt"
# save stdin to file, to use it multiple times
cp /dev/stdin $in_file
# CLASSIFY
res=$(grepmail -B "some regex pattern" < $in_file)
if [ ! -z "$res" ]
then
lista_tag+=("PUSH")
fi
res=$(grepmail -B "some other regex pattern" < $in_file)
if [ ! -z "$res" ]
then
lista_tag+=("MERGIFY")
fi
# ⁝ Many many more similar patterns
# output them comma separated
echo ${lista_tag[*]}
ご覧のとおり、リファクタリングと抽象化の場合があります。res
そしてif .. fi
部分的に繰り返された。しかし、コマンドを安全に渡す方法がわかりません。私がしたいのは、次のような(または同様の)関数を呼び出すことです。
classify '"grepmail -B "somepattern"' 'MYTAG'
しかし、トリッキーです!私が読んでよくある質問しかし、私の場合はうまくいくかわかりません。
したがって、質問は次のようになります。コマンドを渡す正しい方法は何ですか(存在する場合)?res=
そのような機能の一部はどのようなものでしょうか?
答え1
classify '"grepmail -B "somepattern"' 'MYTAG'
で述べたまさにその理由のために作業を始めることは困難です。バッシュFAQ 050。
ただし、「tag」パラメーターを前に置くと、コマンドの残りの部分を使用できるため、機能させることができます。
#!/bin/bash
lista_tag=()
classify() {
local tag="$1"
shift
res=$( "$@" < "$in_file")
if [ -n "$res" ]; then
lista_tag+=("$tag")
fi
}
classify PUSH grepmail -B "some regex pattern"
classify MERGIFY grepmail -B "some other regex pattern"
ここでの核心はまさに私たちです。いいえコマンドの引数を1つの文字列に貼り付けますが、別々に保持します。"$@"
それは魔法です。すべての位置パラメータに個別に拡張されます。タグを削除した後に残ったのはコマンドだけです。
ただし、コマンドを実行して適切に引用する必要があるため、同じ方法でリダイレクトを貼り付けることはできませんeval
。また、ユーザーが入力した入力に対してこの作業を慎重に行う必要があります。そうしないと、コマンド実行の脆弱性が残る可能性が高くなります。
とにかく、そのgrepmail -B
部分は定数のように見えるので、ラベルとモードを渡すだけです。
#!/bin/bash
lista_tag=()
in_file=foo.txt
classify() {
local pattern="$1"
local tag="$2"
if [[ -n "$(grepmail -B "$pattern" < "$in_file")" ]]; then
lista_tag+=("$tag")
fi
}
classify "some regex pattern" PUSH
classify "some other regex pattern" MERGIFY
答え2
これは連想配列を使用する良い機会です。
#!/bin/bash
lista_tag=()
declare -A patterns=(
[PUSH]='some regex pattern'
[MERGIFY]='some other pattern'
# ... other [tag]=pattern pairs ...
)
# capture stdin
in_file=$(mktemp)
cat > $in_file
# CLASSIFY
# iterate over the array indices
for tag in "${!patterns[@]}"; do
if [[ -n "$( grepmail -B "${patterns[$tag]}" < "$in_file" )" ]]; then
lista_tag+=("$tag")
fi
done
# print comma-separated list
( IFS=","; echo "${lista_tag[*]}" )
grepmail
一致するものがない場合(たとえば)、ゼロ以外の終了状態を持つことができる場合は、grep -q
より簡単です。
for tag in "${!patterns[@]}"; do
grepmail -q -B "${patterns[$tag]}" < "$in_file" && lista_tag+=("$tag")
done