목적
목적은 다음 문자열을 변환하는 것입니다.
hello_hello,123-world567-helloworld123456,world1234-hello09876
특정 형식으로 변환하려면 sed를 사용하세요.
노력하다
sed -e 's|^\(hello_[a-z0-9]\{3\}\)\(.*\)|\1,\1\2|g;s|..|&/|g' /tmp/file
예상되는 결과
he/ll/o_/he/ll/o,123-world567-helloworld123456,/wo/rl/d1/23/4-/he/ll/o0/98/76/
현재 결과
문제는 /
2자마다 a가 삽입된다는 점입니다. /
두 개의 쉼표 사이에 삽입을 피하십시오.
he/ll/o_/he/ll/o,/12/3-/wo/rl/d5/67/-h/el/lo/wo/rl/d1/23/45/6,/wo/rl/d1/23/4-/he/ll/o0/98/76/
답변1
나는 이것을 할 수 있다:
sed 's|\(,[^,]*,\)\{0,1\}\([^,]\{1,2\}\)|\1/\2|g
' <<\IN
hello_hello,123-world567-helloworld123456,world1234-hello09876
IN
...인쇄...
/he/ll/o_/he/ll/o,123-world567-helloworld123456,/wo/rl/d1/23/4-/he/ll/o0/98/76
그래서최대두 번째 대체 항목이 변경되었습니다 s///
. 하지만 이는 첫 번째 대체 항목을 모두 제거했기 때문입니다.
따라서 문제의 가장 큰 부분은 두 문자마다 sed
하나씩 바꾸라고 말하는 것입니다 /
.
. 점은 다음을 의미합니다.모든 문자그리고 g
글로벌 의미 - 또는모두.
두 번째로 중요한 부분은 첫 번째 대체가 도움이 되지 않으며 완전히 불필요하다는 것입니다.
뿐만 아니라 첫 번째 교체에 추가 쉼표를 삽입했습니다. 따라서 첫 번째 비트를 알아낸 후에도 여전히 추가 필드가 발생했습니다. 바라보다:
\(,[^,]*,\)\{0,1\}\([^,]\{1,2\}\)|\1/\2
이것은 나에게 적합한 대체 설명이며 그 이유는 다음과 같습니다.
\(,[^,]*,\)\{0,1\}
- 글로벌하게는 조심해서 필요한 만큼만 받아야 합니다. 두 문자마다 교체했으므로 다음과 같은 결과를 얻을 수 있습니다sed
.탐욕스러운. 이것을 먼저 인용하는 것이 중요합니다. 왜냐하면sed
왼쪽에서 오른쪽으로 읽을 때 일반적으로 쉼표가 아닌 두 개의 연속 문자 사이에 슬래시가 삽입되기 때문입니다. 그러나 쉼표가 발견되면 다음 쉼표를 읽고 저장합니다.\1
슬래시를 전혀 삽입하지 않고 전체 블록을 삭제합니다.\([^,]\{1,2\}\)
- 여기에는 점을 사용할 수 없습니다.
. 쉼표와 일치하므로 구분 기호를 건너뛰고 슬래시만 입력하면 됩니다. 쉼표를 명시적으로 제외해야 합니다. 그것이 하는 일입니다 - 1개 또는 2개의 시퀀스마다 -sed
항상 가능한 가장 큰 숫자를 가져옵니다.
이 예와 귀하의 예 사이에서 제가 볼 수 있는 한 가지 차이점은 여기서 첫 번째 슬래시가 문자열의 머리 부분에 있고 후행 슬래시가 없다는 것입니다. 반면에 귀하의 예에서는 그 반대입니다. 필요에 따라 이 문제를 해결하려면 다음을 수행하십시오.
...;s|^/\(.*/.\)/*$|\1/|...
답변2
나는 누군가가 순수한 접근 방식을 생각해 낼 것이라고 확신 sed
하지만, 이런 종류의 작업에서는 단순한 행보다 입력 필드를 이해하는 프로그램을 사용하는 것이 훨씬 쉽다는 것을 알았습니다.
진주
$ perl -F, -lane 'for($F[0],$F[2]){s|(..)|\1/|g;} print join ",",@F' /tmp/file he/ll/o_/he/ll/o,123-world567-helloworld123456,wo/rl/d1/23/4-/he/ll/o0/98/76/
설명하다
-a
: 각 입력 행을 필드로 분할하고@F
배열에 저장합니다. 첫 번째 dt 필드는 첫 번째 dt 필드$F[0]
, 두 번째 필드$F[1]
등이 됩니다 .-F
: 필드 구분 기호를 로 설정합니다,
.-n
및-e
: 각 입력 라인(-n
)을 읽고 에서 제공하는 스크립트를 적용합니다-e
.-l
:후행 줄 바꿈을 제거하고\n
각 호출print
에 a를 추가합니다 .for($F[0],$F[2]){}
:첫 번째와 세 번째 필드에 적용됩니다.s|(..)|\1/|g;
: 간단한 교체로,/
한 문자씩 하나씩 추가됩니다.print join ",",@F'
: 필드 목록을 쉼표로 연결하여 인쇄합니다. 이전 단계에서 필드가 변경되었으므로 변경된 필드가 인쇄됩니다.
GNU awk
$ awk -F, -v OFS="," '{$1=gensub(/(..)/,"\\1/","g",$1); $3=gensub(/(..)/,"\\1/","g",$3);}1;' /tmp/file he/ll/o_/he/ll/o,123-world567-helloworld123456,wo/rl/d1/23/4-/he/ll/o0/98/76/
설명하다
위와 같이
-F
필드 구분자를 설정합니다 .-v OFS=","
출력 구분 기호를 로 설정합니다,
. 그런 다음gensub()
함수(내가 믿는 GNU awk만)가 대체 작업을 실행합니다. 여기서는 첫 번째 및 세 번째 필드에서 작동합니다.