다음과 같은 간단한 스크립트가 있습니다.
- 이메일이 특정 패턴과 일치하는지 확인
- 이 경우 태그 목록에 태그를 추가하세요.
- 종료하기 전에 태그 목록을 인쇄하십시오.
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"
여기서 핵심은 바로 우리다아니요명령의 인수를 하나의 문자열에 붙여넣되 별도로 유지하십시오. "$@"
그것은 마술입니다. 모든 위치 매개변수로 개별적으로 확장됩니다. 태그를 제거하고 나면 남은 것은 명령뿐입니다.
그러나 명령을 실행하고 적절하게 인용해야 하기 때문에 같은 방식으로 리디렉션을 붙여넣을 수는 없습니다 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
일치하는 항목이 없는 경우(예:) 0이 아닌 종료 상태를 가질 수 있으면 grep -q
더 간단합니다 .
for tag in "${!patterns[@]}"; do
grepmail -q -B "${patterns[$tag]}" < "$in_file" && lista_tag+=("$tag")
done