줄 시작 부분의 공백을 "-"로 바꿉니다.

줄 시작 부분의 공백을 "-"로 바꿉니다.
 wqdq
 wqdqgrhehr
 cnkzjncicoajc
 hello space
    oejwfoiwejfow
    wqodojw
    more spaces
    more

이것은 다음 내용으로 만들고 싶은 파일입니다 sed.

-wqdq
-wqdqgrhehr
-cnkzjncicoajc
-hello space
----oejwfoiwejfow
----wqodojw
----more spaces
----more
----
-
--

이를 달성하려면 루프를 사용해야 합니까, 아니면 다른 방법이 있습니까? 나는 이것을 시도했습니다 :

user:~$ sed -n  '
: loop
  s/^ /-/
  s/[^-] /-/p
t loop' spaces

답변1

의 경우 sed다음과 같은 루프가 필요합니다.

sed -e :1 -e 's/^\( *\) /\1-/; t1' < file

아니면 다음과 같이 하세요:

sed '
s/ */&\
/; # add a newline after the leading spaces
h; # save a copy on the hold space
y/ /-/; # replace *every* space with -
G; # append our saved copy
s/\n.*\n//; # remove the superflous part' < file

를 사용하면 perl다음을 수행할 수 있습니다.

perl -pe 's{^ *}{$& =~ y/ /-/r}e' < file

또는

perl -pe 's/(^|\G) /-/g' < file

\GPCRE 일치(너비 없음)에서 이전 일치의 끝( //g컨텍스트 내). 따라서 여기서는 ^줄의 시작이나 이전 일치 항목의 끝 뒤에 오는 공백(즉, 이전에 교체된 공백)을 대체합니다 .

(이 방법은 sedPCRE를 지원하는 구현과 함께 사용할 수도 있습니다 ssed -R.)

를 사용하면 awk다음을 수행할 수 있습니다.

awk '
  match($0, /^ +/) {
    space = substr($0, 1, RLENGTH)
    gsub(" ", "-", space)
    $0 = space substr($0, RLENGTH+1)
  }
  {print}' < file

<space><tab>foo탭 문자를 (예: 로 ) 변환하려는 경우 --------foo전처리된 입력을 사용할 수 있습니다 expand. GNU를 사용하면 줄의 선행 공백에 있는 탭 문자만 변환 expand할 수 있습니다 . expand -i이 옵션을 사용하여 탭 정지 사이의 거리를 지정할 수 있습니다(기본값은 8열마다) -t.

이것을 수평 간격의 모든 문자 또는 최소한 [:blank:]로케일 범주에 속하는 문자로 일반화하는 것은 더 복잡해집니다.

이는 TAB 문자가 없는 경우에만 문제가 됩니다.

perl -Mopen=locale -MText::CharWidth=mbswidth -pe 's/^\h+/"-" x mbswidth($&)/e'

하지만 TAB 문자는제어문자의 너비는 이지만 -1실제로 mbswidth()가지다너비는 행에서의 위치에 따라 1열에서 8열까지 다양합니다.

expand명령은 이를 다음으로 확장합니다.옳은그러나 expand멀티바이트 문자가 있는 경우(예: UTF-8 로케일의 탭과 공백을 제외한 모든 공백 문자) GNU를 포함한 많은 구현에서는 이를 올바르게 처리하지 않으며 멀티바이트 문자를 지원하는 일부 구현에서도 너비가 0이거나 너비가 두 개인 문자( [:blank:]적어도 일반적인 GNU 로케일에서는 U+3000과 같은)로 속입니다 . 따라서 TAB 확장은 다음과 같이 수동으로 수행해야 합니다.

perl -Mopen=locale -MText::CharWidth=mbswidth -pe 's{^\h+}{
  $s = $&;
  while ($s =~ /(.*?)\t(.*)/) {
    $s = $1 . (" " x ((7-mbswidth($1)) % 8 + 1)) . $2;
  }
  "-" x mbswidth($s)}e'

답변2

Stephane이 올바른 sed솔루션을 제공했습니다. 다음은 작고 더 명확한 Python 3 대안입니다.

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as f:
    for line in f:
        beginning = True
        for char in line:
            if beginning and char == " ":
                print("-",end="")
            else:
               beginning = False
               print(char,end="")

테스트 실행:

# This is the input text
$ cat -A input.txt
 wqdq$
 wqdqgrhehr$
 cnkzjncicoajc$
 hello space$
    oejwfoiwejfow$
    wqodojw$
    more spaces$
    more$
    $
 $
  $

# And this is the output with the given python script
$ ./add_dashes.py ./input.txt                                                                                            
-wqdq
-wqdqgrhehr
-cnkzjncicoajc
-hello space
----oejwfoiwejfow
----wqodojw
----more spaces
----more
----
-
--

답변3

또 다른 awk방법:

awk 'match($0, /^[[:space:]]+/){ p=""; l=RLENGTH; while(l--) p=p"-";
     sub(/^[[:space:]]+/,p); print}' yourfile

산출:

-wqdq
-wqdqgrhehr
-cnkzjncicoajc
-hello space
----oejwfoiwejfow
----wqodojw
----more spaces
----more
----
-
--

match($0, /^[[:space:]]+/)- 선행 공백이 있는 시퀀스와 일치합니다.

l=RLENGTH- 라인당 일치하는 시퀀스의 크기

while(l--) p=p"-"- 대체 하위 문자열 구성



선택하다파이썬3.x 방법:

하이픈.py에 공백스크립트:

import sys, re
with open(sys.argv[1], 'r') as f:  # reading input file
    for l in f.read().splitlines():
        m = re.match(r'^ +', l)    # capture sequence of leading spaces 
        print(l if not m else l.replace(' ', '-', m.end()))

용법:

python3 space_to_hyphen.py yourfile

답변4

피복재

루프 를 설정하고 do-while줄에 여전히 선행 공백이 있는 동안 공백이 아닌 첫 번째 공백에 인접한 마지막 공백을 계속 변환합니다.

sed -e '
   :loop
      /^ /s/ \([^ ]\|$\)/-\1/
   tloop
' filename.ext


while IFS= read -r l; do
   read -r ll <<<"$(printf '%ss\n' "$l")"
   printf '%s%s\n' \
      "$(seq -s= 0 "$(expr "$l" : '[   ]*')" | tr = - | tr -cd -)" \
      "${ll%?}"
done < filename.ext

결과

-wqdq
-wqdqgrhehr
-cnkzjncicoajc
-hello space
----oejwfoiwejfow
----wqodojw
----more spaces
----more
----
-
--

작동 원리

  • while파일을 한 줄씩 읽도록 루프를 설정 하고 IFS로 설정합니다 NULL. 이것의 목적은 줄의 모든 공백을 유지하는 것입니다.
  • 다음으로 기본값을 사용하여 동일한 행의 더미 읽기를 수행합니다 IFS. 이렇게 하면 선행 공백이 잘립니다. 명령 확장 단계에서 후행 줄 바꿈으로 인한 충돌을 방지하기 위해 줄 바꿈이 아닌 더미 문자를 끝에 추가합니다. 인쇄할 때 벗겨냅니다.
  • expr명령의 목적은 일치하는 항목의 수를 찾는 것입니다. 이 경우에는 줄의 앞쪽 가장자리에 있는 공백입니다.
  • 이 숫자를 사용하여 적절한 설정 seqtr명령이 포함된 일련의 대시를 생성합니다.
  • 마지막으로 trimmed기본 IFS를 통해 읽은 줄과 함께 대시를 인쇄합니다.

관련 정보