sed 표현식에 쉘 명령을 포함시키는 방법은 무엇입니까? 다음 형식의 텍스트 파일이 있습니다. keyword value keyword

다음 형식의 텍스트 파일이 있습니다.

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;"

그리고 그것은 작동합니다.