sed가 \ t를 탭으로 인식하지 않는 이유는 무엇입니까?


105
sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename

sed스크립트가 tab모든 줄 앞에 삽입 될 것으로 예상하고 $filename있지만 그렇지 않습니다. 어떤 이유로 t대신에 삽입 됩니다.


1
sed는 플랫폼 (특히 BSD / MacOSX 대 Linux)마다 다를 수 있으므로 sed를 사용하는 플랫폼을 지정하는 것이 도움이 될 수 있습니다.
Isaac

sed "s / (. *) / # \ 1 /"$ filename | tr '#' '\ t'> $ sedTmpFile && mv $ sedTmpFile $ filename.
user2432405

OS X (macOS) 사용자의 경우이 질문을 참조하십시오 .
Franklin Yu

답변:


129

모든 버전이 sed이해되는 것은 아닙니다 \t. 대신 리터럴 탭을 삽입하십시오 ( Ctrl- V다음을 누름 Tab).


2
아 예; 명확히하기 위해 : sed의 모든 버전이 \t표현식의 대체 부분을 이해하는 것은 아닙니다 ( \t패턴 일치 부분에서 잘 인식됨 )
John Weldon

3
awwwwwwwwwwwwwwwwwww, 꽤 흥미 롭군요. 그리고 이상합니다. 왜 한 곳에서는 인식하고 다른 곳에서는 인식하지 못하도록 만들까요 ...?
sixtyfootersdude 2010

2
스크립트에서 호출하면 작동하지 않습니다. sh는 탭을 무시합니다. 예를 들어, 쉘 스크립트의 다음 코드는 테이블 앞에 추가하지 않고 $ TEXT_TO_ADD를 추가합니다. sed "$ {LINE} a \\ $ TEXT_TO_ADD"$ FILE.
Dereckson 2013-01-23

2
@Dereckson 및 기타-이 답변 참조 : stackoverflow.com/a/2623007/48082
Cheeso

2
Dereckson s / can / ca n't /?
Douglas는

41

Bash를 사용하면 다음과 같이 프로그래밍 방식으로 TAB 문자를 삽입 할 수 있습니다.

TAB=$'\t' 
echo 'line' | sed "s/.*/${TAB}&/g" 
echo 'line' | sed 's/.*/'"${TAB}"'&/g'   # use of Bash string concatenation

이것은 매우 도움이됩니다.
Cheeso

1
당신은 올바른 길을 $'string'가고 있었지만 설명이 부족 했습니다 . 사실 나는 당신이 아마도 불완전한 이해를 가지고 있다는 극도로 어색한 사용법 때문에 (대부분의 bash와 같이) 의심합니다. : 아래에있는 내 설명을 참조하십시오 stackoverflow.com/a/43190120/117471
브루노 Bronosky

1
BASH는 $TAB작은 따옴표 내부 와 같은 변수를 확장하지 않으므로 큰 따옴표를 사용해야합니다.
nealmcb

*큰 따옴표 를 사용하는 데주의하십시오 . 이것은 의도 한 정규식이 아닌 glob으로 처리됩니다.
levigroker

27

@sedit는 올바른 경로에 있었지만 변수를 정의하는 것은 약간 어색합니다.

솔루션 (bash 특정)

bash에서이 작업을 수행하는 방법은 작은 따옴표로 묶인 문자열 앞에 달러 기호를 넣는 것입니다.

$ echo -e '1\n2\n3'
1
2
3

$ echo -e '1\n2\n3' | sed 's/.*/\t&/g'
t1
t2
t3

$ echo -e '1\n2\n3' | sed $'s/.*/\t&/g'
    1
    2
    3

문자열에 변수 확장이 포함되어야하는 경우 다음과 같이 인용 된 문자열을 함께 넣을 수 있습니다.

$ timestamp=$(date +%s)
$ echo -e '1\n2\n3' | sed "s/.*/$timestamp"$'\t&/g'
1491237958  1
1491237958  2
1491237958  3

설명

bash에서 $'string'"ANSI-C 확장"이 발생합니다. 그리고 우리가 같은 것들을 사용할 때 우리의 대부분이 기대하는 것입니다 \t, \r, \n:에서 등 https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html#ANSI_002dC-Quoting

$ 'string' 형태의 단어는 특별히 취급됩니다. 이 단어 는 ANSI C 표준에 지정된대로 백 슬래시 이스케이프 문자가 대체 된 문자열 로 확장됩니다 . 백 슬래시 이스케이프 시퀀스 (있는 경우)가 디코딩됩니다.

확장 된 결과는 달러 기호가없는 것처럼 작은 따옴표로 표시됩니다.

솔루션 (bash를 피해야하는 경우)

나는 개인적으로 bashsms를 피하는 것이 코드를 이식 가능하게 만들지 않기 때문에 bash를 피하려는 대부분의 노력이 어리 석다고 생각합니다. (당신이 bash -eubash를 피하고 sh[당신이 절대적인 POSIX 닌자가 아니라면] 사용하려고 시도 하는 것보다 당신의 코드를 흘리면 덜 부서 질 것 입니다.) 그러나 그것에 대해 종교적인 논쟁을하기보다는, 나는 당신에게 최선을 줄 것입니다. * 대답.

$ echo -e '1\n2\n3' | sed "s/.*/$(printf '\t')&/g"
    1
    2
    3

* 최고의 답변? 예, 대부분의 안티 bash 쉘 스크립터가 코드에서 잘못하는 한 가지 예는 @robrecord의 답변echo '\t' 에서와 같이 사용 하는 입니다. GNU 에코에서는 작동하지만 BSD 에코에서는 작동하지 않습니다. 이는 The Open Group ( http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16) 에서 설명합니다. 이것이 바로 바 시즘을 피하려는 시도가 보통 실패하는 이유의 예입니다.


8

Ubuntu 12.04 (LTS)에서 Bash 셸과 함께 다음과 같은 것을 사용했습니다.

탭이 있는 새 줄을 추가하려면 첫 번째 항목 이 일치 할 때 번째 :

sed -i '/first/a \\t second' filename

firsttab, second로 바꾸려면 다음을 수행하십시오 .

sed -i 's/first/\\t second/g' filename

4
이중 이스케이프 키, 즉 사용하는 것입니다 \\t하지 \t.
zamnuts

또한 Ubuntu 16.04 및 Bash 4.3에서 작은 따옴표 대신 큰 따옴표를 사용해야했습니다.
caw

4

사용 $(echo '\t'). 패턴 주위에 따옴표가 필요합니다.

예 : 탭을 제거하려면 :

sed "s/$(echo '\t')//"

5
"GNU echo"특정 기능 (\ t를 탭 문자로 해석)을 사용하여 "BSD sed"특정 버그 (\ t를 2 개의 개별 문자로 해석)를 해결하는 것은 재밌습니다. 아마도 "GNU echo"가 있으면 "GNU sed"도있을 것입니다. 어떤 경우에는 echo를 사용할 필요가 없습니다. BSD 에코 echo '\t'는 2 개의 개별 문자를 출력합니다. POSIX 이식 가능한 방법은 printf '\t'. 이것이 내가 말하는 이유입니다. bash를 사용하지 않고 코드를 이식 가능하게 만들려고하지 마십시오. 생각보다 어렵습니다. 사용 bash은 우리 대부분이 할 수있는 가장 휴대하기 쉬운 일입니다.
Bruno Bronosky 2017

3

sed실제로는 행 앞에 탭을 삽입하고 싶을 때 대체를 수행하는 데 사용할 필요가 없습니다 . 이 경우를 대체하는 것은 특히 큰 파일로 작업 할 때 인쇄하는 것보다 비용이 많이 드는 작업입니다. 정규식이 아니기 때문에 읽기도 쉽습니다.

예 : awk 사용

awk '{print "\t"$0}' $filename > temp && mv temp $filename


0

sed는 지원하지 \t않으며 다른 이스케이프 시퀀스도 지원하지 않습니다 \n. 내가 찾은 유일한 방법은 실제로를 사용하여 스크립트에 탭 문자를 삽입하는 것 sed입니다.

즉, Perl 또는 Python 사용을 고려할 수 있습니다. 다음은 모든 스트림 정규식에 사용하는 짧은 Python 스크립트입니다.

#!/usr/bin/env python
import sys
import re

def main(args):
  if len(args) < 2:
    print >> sys.stderr, 'Usage: <search-pattern> <replace-expr>'
    raise SystemExit

  p = re.compile(args[0], re.MULTILINE | re.DOTALL)
  s = sys.stdin.read()
  print p.sub(args[1], s),

if __name__ == '__main__':
  main(sys.argv[1:])

2
그리고 Perl 버전은 쉘 한 줄짜리 "perl -pe 's / a / b /'filename"또는 "something | perl -pe 's / a / b /'"입니다
tiftik 2010

0

BSD sed 대신 perl을 사용합니다.

ct@MBA45:~$ python -c "print('\t\t\thi')" |perl -0777pe "s/\t/ /g"
   hi

0

나는 다른 사람들이 다른 방법 (위해 적절하게이 문제를 명확히 한 생각 sed, AWK등). 그러나 내 bash특정 답변 (macOS High Sierra 및 CentOS 6/7에서 테스트 됨)은 다음과 같습니다.

1) OP가 원래 제안한 것과 유사한 검색 및 바꾸기 방법을 사용하려면 perl다음과 같이 사용 하는 것이 좋습니다 . 참고 : 정규식 괄호 앞에 백 슬래시 필요는 없습니다,이 코드 라인이 어떻게 반영 $1보다 사용하기 더 \1perl대체 연산자 (예 : 당 펄 5 문서 ).

perl -pe 's/(.*)/\t$1/' $filename > $sedTmpFile && mv $sedTmpFile $filename

2) 그러나 ghostdog74 에서 지적했듯이 원하는 작업은 실제로 tmp 파일을 입력 / 대상 파일 ( )로 변경하기 전에 각 줄의 시작 부분에 추가하는$filename 것이므로 perl다시 권장 하지만 다음과 같이 수정합니다. (에스):

perl -pe 's/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename
## OR
perl -pe $'s/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename

3) 물론, tmp 파일은 불필요 하므로 모든 것을 '제자리'( -i플래그 추가 )하고 다음을 사용하여 더 우아한 한 줄로 단순화하는 것이 좋습니다.

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