마지막 x 발생을 제외한 문자 교체


9

다음과 같은 IP와 상호 관련된 많은 호스트 이름을 가진 파일이 있습니다.

x-cluster-front-1 192.168.1.2
x-cluster-front-2 192.158.1.10
y-cluster-back-1 10.1.11.99
y-cluster-back-2 10.1.157.38
int.test.example.com 59.2.86.3
super.awesome.machine 123.234.15.6

나는 다음과 같이 보이기를 원한다.

x-cluster-front-1 192.168.1.2
x-cluster-front-2 192.158.1.10
y-cluster-back-1 10.1.11.99
y-cluster-back-2 10.1.157.38
int-test-example-com 59.2.86.3
super-awesome-machine 123.234.15.6

을 어떻게 교체 할 수 있습니까? 두 번째 열에 의한 정렬을 용이하게하기 위해 첫 번째 열의-(하이픈)으로 (점)? sed를 사용하여 첫 번째 공백까지 점을 교체하거나 마지막 3 점을 제외한 모든 점을 교체하려고 생각했지만 정규 표현식과 sed를 이해하는 데 어려움이 있습니다. 나는 간단한 교체를 할 수 있지만 이것은 내 머리 위로입니다!

이것은 내가 bash로 쓰고있는 더 큰 스크립트의 일부입니다. 나는이 부분에 갇혀있다.

답변:


7

AWK를 사용할 수 있습니다

awk '{gsub(/-/,".",$1);print}' infile

설명

awk기본적으로 공백을 공백으로 분할합니다. 따라서, (라인의 첫 번째 열 $1에서 awk-ese)는에 대체를 수행 할 하나가 될 것입니다. 이를 위해 다음을 사용할 수 있습니다.

 gsub(regex,replacement,string)

필요한 대체를 수행합니다.

참고 gsub만 지원 gawk하고 nawk있지만, 많은 현대 배포판에은 awk에 소프트 링크입니다 gawk.


1
+1 나에게 이겼다. 나는 설명이 진정으로 미래의 독자들에게도 도움이 될 것이라고 생각합니다.
Joseph R.

1
@JosephR. 설명이 좋지 않지만 죄송합니다.
Rahul Patil

2
의 POSIX 사양은를 awk기반으로 nawk하므로 모든 최신 awk구현에는 있어야 gsub합니다. Solaris에서는 /usr/xpg4/bin/awk또는 이 필요할 수 있습니다 nawk.
Stéphane Chazelas

@RahulPatil 마음에 들지 않으면 다른 사람들을 도울 것이라고 생각되는 몇 줄을 추가했습니다.
Joseph R.

@JosephR 감사합니다 .., 그것은 지금 완벽 해 보인다 .. :)
Rahul Patil

6

첫 번째 필드에서 대체를 수행 해야하는 경우 가장 좋은 방법은 Rahul의 awk 솔루션 을 사용하는 것이지만 간격에 영향을 줄 수 있습니다 (필드는 사이에 단일 공백으로 다시 작성 됨).

대신 작성하여 피할 수 있습니다.

perl -pe 's|\S+|$&=~tr/./-/r|e' file

-p플래그 수단은 "라인으로 입력 파일 라인을 읽고에 의해 주어진 스크립트를 적용한 후 각 행을 인쇄 -e". 이어서, 대체 ( s|pattern|replacement|) 비 공백 문자의 제 1 시퀀스 ( \S+일치하는 패턴 ()와 $&모든 치환 후) .-. 요령은 연산자가 표현식을 대체물로 평가할 s|||e위치 를 사용 하는 e것입니다. 따라서 이전 tr/./-/항목 ( $&)의 일치 항목 ( )에 하나의 대체품 ( )을 적용 할 수 있습니다 s|||e.

당신이 모든 대체해야하는 경우 .A의를 -GNU로, 지난 3 마지막을 제외한 sed및 가정 당신은이 rev명령을 :

rev file | sed 's/\./-/4g' | rev

1
Perl 솔루션은 버전 5.14 이상 ( /r작동하려면)을 가정합니다.
Joseph R.

3

Sed는 작업에 가장 쉬운 도구는 아니지만 더 나은 도구에 대해서는 다른 답변을 참조하십시오.

교체 방법 .에 의해 -에만 최대 최초의 우주, 사용에 s루프한다.

sed -e '
  : a                     # Label "a" for the branching command
  s/^\([^ .]*\)\./\1-/    # If there is a "." before the first space, replace it by "-"
  t a                     # If the s command matched, branch to a
'

(일부 sed 구현은 동일한 행에 대한 주석을 지원하지 않습니다. GNU sed는 지원합니다.)

대신 마지막 공간까지 교체를 수행하려면

sed -e '
  : a                     # Label "a" for the branching command
  s/\.\(.* \)/-\1/        # If there is a "." before the last space, replace it by "-"
  t a                     # If the s command matched, branch to a
'

다른 기술은 sed의 유지 공간을 사용합니다. 홀드 공간에 수정하고 싶지 않은 비트를 저장하고 작업을 한 다음 홀드 공간을 불러옵니다. 여기에서는 마지막 공간에서 선을 나누고 첫 번째 부분에서 점을 대시로 바꿉니다.

sed -e '
  h           # Save the current line to the hold space
  s/.* / /    # Remove everything up to the last space
  x           # Swap the work space with the hold space
  s/[^ ]*$//  # Remove everything after the last space
  y/./-/      # Replace all "." by "-"
  G           # Append the content of the hold to the work space
  s/\n//      # Remove the newline introduced by G
'

2

Rahul이 유스 케이스에 대한 정식 답변 을 줬기 때문에 나는 정규 문제의 마지막 x 발생을 제외한 모든 문제를 대치하여 다음과 같은 문제에 답할 것이라고 생각했습니다.

perl -pe '
    $count = tr{.}{.}; # Count '.' on the current line
    $x = 3;
    next LINE if $count <= $x;
    while(s{\.}{-}){   # Substitute one '.' with a '-'
        last if ++$i == $count - $x # Quit the loop before the last x substitutions
    }
$i = 0
' your_file

위의 코드 (테스트 된)는 공백으로 구분 된 필드가 있다고 가정하지 않습니다. 마지막 3 개의 점을 제외하고 선의 모든 점을 대시로 바꿉니다. 3코드를 원하는대로 교체하십시오 .


2

이를 위해 다양한 도구를 사용할 수 있습니다. Rahul Patil은 이미 당신에게 gawk하나를 주었 으므로 여기에 다른 몇 가지가 있습니다.

  • perl -lane  '$F[0]=~s/\./-/g; print "@F"' file
    

    -a스위치로 인해 perl은 공백에서 입력 행을 자동으로 분할하고 결과 필드를 배열에 저장합니다 @F. 첫 번째 필드 그러므로이 될 것입니다 $F[0]우리가 (대체 있도록 s///)의 모든 항목을 .함께 -첫 번째 필드에 다음 전체 배열을 인쇄 할 수 있습니다.

  • 껍질

     while read -r a b; do printf "%s %s\n" "${a//./-}" "$b"; done < file 
    

    여기서, while 루프는 파일을 읽고 자동으로 whitespace.This은 두 개의 필드를 생성에 분할, $first하고 $rest. 이 구문 ${first//pattern/replacement}은 모든 항목을 pattern로 바꿉니다 replacement.


+1 "자동 분할 모드" perlrun(1)라고 말하지만 -a, " awk모드" 로 생각하고 싶습니다 . : D
Joseph R.

2

나는 이것이 큰 불쾌한 정규 표현식보다 읽기가 더 쉽다고 생각합니다. 기본적으로 나는 공백을 두 칸으로 나누고 첫 번째 부분에서 sed를 사용합니다.

while read -r host ip; do
    echo "$(sed 's/\./-/g' <<< "$host") $ip"
done < input_file

쉘에 따라 sed 명령 대신 $ {host //./-}를 사용할 수도 있습니다.


0
sed 's/\./-/' <file name>

g명령의 끝에서 사용 하지 않고이 작업을 수행 할 수 있습니다. 이것은 패턴의 첫 번째 발생을 대체합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.