다음 형식의 텍스트 파일이 있습니다.
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`
.
답변
표준 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
선 마이너스 후행 공백의 나머지.
변수 참조를 확장하지만 명령 대체 외부에서 명령을 실행하지 않으려면 here document$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
here 문서와 함께 키워드를 이스케이프 처리해야합니다 (그러나 다르게).
{
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
데이터가 많은 경우 가장 빠른 방법입니다. 각 라인마다 별도의 프로세스를 시작하지 않습니다.
어 wk
sed 작업에 awk를 사용한 것과 동일한 기술. 결과 프로그램은 훨씬 더 읽기 쉽습니다. “로 이동echo \2
“로 이동 :
awk '
1 {
kw = $1;
sub(/^ *[^ ]+ +/, "");
gsub(/\047/, "\047\\\047\047", $1);
print "echo \047k=<" kw ">\047 v=\\<" $0 "\\>";
}' | sh
here 문서 사용하기 :
awk '
NR==1 { print "cat <<EOF" }
1 {
kw = $1;
sub(/^ *[^ ]+ +/, "");
gsub(/\\\$`/, "\\&", $1);
print "k=<" kw "> v=<" $0 ">";
}
END { print "EOF" }
' | sh
답변
GNU sed
를 사용하면 다음 명령을 사용할 수 있습니다.
sed -nr 's/([^ ]+) (.*)/echo "\1" \2\n/ep' input
어떤 출력 :
keyword value value
keyword value value
keyword Linux
입력 데이터와 함께.
설명:
sed 명령은 -n
옵션을 사용하여 일반 출력을 억제합니다 . -r
확장 정규 표현식을 사용하도록 전달되어 패턴에서 특수 문자를 이스케이프 처리 할 수는 있지만 필수는 아닙니다.
이 s
명령은 입력 행을 명령으로 전송하는 데 사용됩니다.
echo "\1" \2
키워드는 값을 인용하지 않습니다. sed에게 대체 결과를 쉘 명령으로 실행하고 결과를 패턴 버퍼 (여러 행)로 읽도록 지시 e
하는 s
명령에 GNU 고유 의 옵션을 전달합니다 . 옵션 사용 p
후하는 (!) e
하게 sed
명령이 실행 된 후 패턴 버퍼를 인쇄.
답변
이 방법을 시도해 볼 수 있습니다.
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
) 여기서 처리는 예상되는 메시지를 출력하는 기능이다.
답변
sed가 아닌 솔루션이 허용 가능한 경우이 PERL 스 니펫이 다음 작업을 수행합니다.
$ echo "$input" | perl -ne 'chomp; /^\s*(.+?)\s+(.+)$/ && do { $v=`echo "$2"`; chomp($v); print "k=<$1> v=<$v>\n"}'
답변
키스 숏 퓨어 SED 만
난 이걸 할거야
echo "ls_me" | sed -e "s/\(ls\)_me/\1/e" -e "s/to be/continued/g;"
그리고 그것은 작동합니다.