나는 이 문자열을 가지고 있습니다 :
update mytable set mycol=myvalue where mycol=yourvalue;
다음으로 변환해야 합니다.
insert into mytemp select * from mytable where mycol=youvalue;
나는 이렇게 할 수 있고 훌륭하게 작동합니다.
sed -e 's/^Update.*where//ig' -e "s/^/insert into mytemp select * from mytable where /g" n.txt
하지만:
문자열이 다음과 같은 경우:
update mytable set mycol=myvalue where mycol=(select yourcol from yourtable where youcol=yourvalue);
나는 얻다:
insert into mytemp select * from mytable where youcol=yourvalue);
그리고 나는 원한다:
insert into mytemp select * from mytable where mycol=(select yourcol from yourtable where youcol=yourvalue);
어떡해?
답변1
기본적으로 sed
정규식 엔진은 탐욕적입니다. 이는 패턴이 항상 가능한 가장 긴 일치 항목과 일치함을 의미합니다. 탐욕스럽지 않은 검색을 해야 하는데 sed가 탐욕스럽지 않은 검색을 지원하지 않는 것 같습니다. 따라서 sed
가능한 가장 짧은 일치 항목을 찾을 수 있도록 검색 패턴에 피벗 포인트를 추가해야 합니다 .
다음 줄은 탐욕스럽지 않은 특수한 일치를 시뮬레이션하려고 시도하며, w
첫 번째와 첫 번째 사이의 단일이 패턴을 무효화하므로 일반성이 필요하지 않습니다.update
where
sed -e 's/^Update[^w]*where//ig'\
-e "s/^/insert into mytemp select * from mytable where /g" n.txt
perl
및 중 하나 와 같은 다른 정규식 엔진은 이 기능을 지원합니다 awk
.
하지만 당신의 경우에는 다음과 같은 표현이 필요하다고 생각합니다.
sed -e 's/^Update.\+where\(.\+where.*\)$/\
insert into mytemp select * from mytable where \1/ig' n.txt
귀하의 특정 질문에 더 편리할 것입니다.
(위 라인의 예고편은 \
라인을 더 명확하게 하기 위해 추가되었습니다.)
답변2
정규식 일치는 왼쪽에서 오른쪽으로 진행되며 가장 긴 일치 항목에 우선순위를 부여합니다. 따라서 해당 줄 ^Update.*where
의 마지막 항목 과 일치합니다.where
이 일치를 수행하는 한 가지 방법은 non-greedy 수량자를 사용하는 것입니다 *
. Sed는 non-greedy 수량자를 지원하지 않지만 Perl은 지원합니다.
perl -pe 's/^update.*?where//i; s/^/insert into mytemp select .*? from mytable where /'
데이터와 일치할 수도 있고 일치하지 않을 수도 있는 또 다른 접근 방식은 테이블 이름과 열 설정에서 괄호를 거부하는 것입니다.
sed -e 's/^update[^()]*where//i' -e 's/^/insert into mytemp select [^()]* from mytable where /'
보다 정교한 접근 방식은 먼저 where
첫 번째 토큰을 고유한 토큰으로 바꾼 다음 대체를 수행하고 마지막으로 토큰을 로 복원하는 것입니다 where
. sed는 한 줄씩 실행되므로 \n
다음과 같이 줄에 개행 문자가 포함되지 않는 것이 보장됩니다. sed.
sed -e 's/ where /\n/' \
-e 's/^update.*$//i' -e 's/^/insert into mytemp select .* from mytable where /' \
-e 's/\n/ where/'