다음 형식의 텍스트 파일이 있습니다.
keyword value
keyword value
...
여기서 키는 단일 단어이고 값은 줄이 끝나기 전의 모든 항목입니다. (키워드가 아닌) 값을 쉘 확장에 적용하여 쉘 스크립트에서 파일을 읽고 싶습니다.
sed를 사용하여 키워드와 값 부분을 쉽게 일치시키세요
input='
keyword value value
keyword "value value"
keyword `uname`
'
echo "$input"|sed -e 's/^\([^[:space:]]*\)[[:space:]]\(.*\)$/k=<\1> v=<\2>/'
생산하다
k=<keyword> v=<value value>
k=<keyword> v=<"value value">
k=<keyword> v=<`uname`>
그러나 문제는 sed 표현식의 대체 부분에 쉘 명령을 포함시키는 방법입니다. 이 경우에는 \1 `echo \2`
.
답변1
GNU를 사용하면 sed
다음 명령을 사용할 수 있습니다.
sed -nr 's/([^ ]+) (.*)/echo "\1" \2\n/ep' input
어떤 출력:
keyword value value
keyword value value
keyword Linux
귀하의 입력 데이터로.
설명하다:
-n
일반 출력을 억제하려면 sed 명령과 함께 이 옵션을 사용하십시오 . -r
패턴에서 특수 문자의 일부 이스케이프를 방지하는 확장 정규식을 사용하려면 전달하지만 필수는 아닙니다.
이 s
명령은 입력 행을 명령으로 변환하는 데 사용됩니다.
echo "\1" \2
키워드는 인용되고 값은 인용되지 않습니다. sed에게 대체 명령을 쉘 명령으로 실행하고 그 결과를 패턴 버퍼(여러 줄 포함)로 읽도록 지시하는 명령 e
에 옵션(GNU 관련) 을 전달합니다 . 명령을 실행한 후 패턴 버퍼를 인쇄 하려면 after(!) 옵션을 s
사용하십시오 .p
e
sed
답변2
표준 sed는 쉘을 호출할 수 없습니다(이 작업을 수행하는 GNU sed 확장이 있습니다., 임베디드 Linux에만 관심이 있는 경우) sed 외부에서 일부 처리를 수행해야 합니다. 여러 가지 해결책이 있습니다. 모두 주의 깊게 인용해야 합니다.
이러한 값을 어떻게 확장하려는지 명확하지 않습니다. 예를 들어 행이 다음과 같은 경우
foo hello; echo $(true) 3
다음 중 어떤 결과가 나와야 합니까?
k=<foo> value=<hello; echo 3>
k=<foo> value=<hello; echo 3>
k=<foo> value=<hello; echo 3>
k=<foo> value=<foo hello
3>
아래에서 몇 가지 가능성에 대해 논의하겠습니다.
순수한 껍질
쉘이 입력을 한 줄씩 읽고 처리하도록 할 수 있습니다. 이것은 가장 간단한 솔루션이자 짧은 파일의 경우 가장 빠른 솔루션입니다. 이는 귀하의 요구 사항 " echo \2
"에 가장 가깝습니다.
while read -r keyword value; do
echo "k=<$keyword> v=<$(eval echo "$value")>"
done
read -r keyword value
$keyword
줄의 첫 번째 공백으로 구분된 단어와 $value
줄의 나머지 부분에서 후행 공백을 뺀 단어로 설정됩니다 .
변수 참조를 확장하고 싶지만 명령 대체 이외의 명령은 수행하지 않으려면 $value
다음을 입력하십시오 .여기 문서. 나는 이것이 당신이 정말로 원하는 것이라고 생각합니다.
while read -r keyword value; do
echo "k=<$keyword> v=<$(cat <<EOF
$value
EOF
)>"
done
sed가 쉘로 파이프됨
입력을 셸 스크립트로 변환하고 평가할 수 있습니다. Sed는 쉽지는 않지만 작업을 수행합니다. " " 요구 사항 충족 echo \2
(키워드에서 작은따옴표를 이스케이프해야 함):
sed -e 's/^ *//' -e 'h' \
-e 's/[^ ]* *//' -e 'x' \
-e 's/ .*//' -e "s/'/'\\\\''/g" -e "s/^/echo 'k=</" \
-e 'G' -e "s/\n/>' v=\\</" -e 's/$/\\>/' | sh
이 문서에서는 여전히 키워드를 이스케이프 처리해야 합니다(그러나 다르게).
{
echo 'cat <<EOF'
sed -e 's/^ */k=</' -e 'h' \
-e 's/[^ ]* *//' -e 'x' -e 's/ .*//' -e 's/[\$`]/\\&/g' \
-e 'G' -e "s/\n/> v=</" -e 's/$/>/'
echo 'EOF'
} | sh
데이터가 많은 경우 이 방법이 가장 빠른 방법입니다. 행마다 별도의 프로세스를 시작하지 않습니다.
앗
sed에서 사용하는 기술은 awk에서 사용하는 기술과 동일합니다. 결과 프로그램은 훨씬 더 읽기 쉽습니다. 함께 echo \2
:
awk '
1 {
kw = $1;
sub(/^ *[^ ]+ +/, "");
gsub(/\047/, "\047\\\047\047", $1);
print "echo \047k=<" kw ">\047 v=\\<" $0 "\\>";
}' | sh
여기에서 문서를 사용하세요.
awk '
NR==1 { print "cat <<EOF" }
1 {
kw = $1;
sub(/^ *[^ ]+ +/, "");
gsub(/\\\$`/, "\\&", $1);
print "k=<" kw "> v=<" $0 ">";
}
END { print "EOF" }
' | sh
답변3
다음 방법을 시도해 볼 수 있습니다.
input='
keyword value value
keyword "value value"
keyword `uname`
'
process() {
k=$1; shift; v="$*"
printf '%s\n' "k=<$k> v=<$v>"
}
eval "$(printf '%s\n' "$input" | sed -n 's/./process &/p')"
(당신의 의도를 이해한다면). 즉, 비어 있지 않은 각 줄의 시작 부분에 "process"를 삽입하여 다음과 같은 스크립트로 만듭니다.
process keyword value value
process keyword "value value"
process keyword `uname`
평가 대상( eval
)프로세스예상되는 메시지를 인쇄하는 함수입니다.
답변4
ONLY KISS 쇼트 퓨어 SED
내가 할게
echo "ls_me" | sed -e "s/\(ls\)_me/\1/e" -e "s/to be/continued/g;"
그리고 그것은 작동합니다.