sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
이 sed
스크립트가 tab
모든 줄 앞에 삽입 될 것으로 예상하고 $filename
있지만 그렇지 않습니다. 어떤 이유로 t
대신에 삽입 됩니다.
sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
이 sed
스크립트가 tab
모든 줄 앞에 삽입 될 것으로 예상하고 $filename
있지만 그렇지 않습니다. 어떤 이유로 t
대신에 삽입 됩니다.
답변:
모든 버전이 sed
이해되는 것은 아닙니다 \t
. 대신 리터럴 탭을 삽입하십시오 ( Ctrl- V다음을 누름 Tab).
\t
표현식의 대체 부분을 이해하는 것은 아닙니다 ( \t
패턴 일치 부분에서 잘 인식됨 )
Bash를 사용하면 다음과 같이 프로그래밍 방식으로 TAB 문자를 삽입 할 수 있습니다.
TAB=$'\t'
echo 'line' | sed "s/.*/${TAB}&/g"
echo 'line' | sed 's/.*/'"${TAB}"'&/g' # use of Bash string concatenation
$'string'
가고 있었지만 설명이 부족 했습니다 . 사실 나는 당신이 아마도 불완전한 이해를 가지고 있다는 극도로 어색한 사용법 때문에 (대부분의 bash와 같이) 의심합니다. : 아래에있는 내 설명을 참조하십시오 stackoverflow.com/a/43190120/117471
$TAB
작은 따옴표 내부 와 같은 변수를 확장하지 않으므로 큰 따옴표를 사용해야합니다.
*
큰 따옴표 를 사용하는 데주의하십시오 . 이것은 의도 한 정규식이 아닌 glob으로 처리됩니다.
@sedit는 올바른 경로에 있었지만 변수를 정의하는 것은 약간 어색합니다.
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 표준에 지정된대로 백 슬래시 이스케이프 문자가 대체 된 문자열 로 확장됩니다 . 백 슬래시 이스케이프 시퀀스 (있는 경우)가 디코딩됩니다.
확장 된 결과는 달러 기호가없는 것처럼 작은 따옴표로 표시됩니다.
나는 개인적으로 bashsms를 피하는 것이 코드를 이식 가능하게 만들지 않기 때문에 bash를 피하려는 대부분의 노력이 어리 석다고 생각합니다. (당신이 bash -eu
bash를 피하고 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) 에서 설명합니다. 이것이 바로 바 시즘을 피하려는 시도가 보통 실패하는 이유의 예입니다.
Ubuntu 12.04 (LTS)에서 Bash 셸과 함께 다음과 같은 것을 사용했습니다.
탭이 있는 새 줄을 추가하려면 첫 번째 항목 이 일치 할 때 두 번째 :
sed -i '/first/a \\t second' filename
first 를 tab, second로 바꾸려면 다음을 수행하십시오 .
sed -i 's/first/\\t second/g' filename
\\t
하지 \t
.
사용 $(echo '\t')
. 패턴 주위에 따옴표가 필요합니다.
예 : 탭을 제거하려면 :
sed "s/$(echo '\t')//"
echo '\t'
는 2 개의 개별 문자를 출력합니다. POSIX 이식 가능한 방법은 printf '\t'
. 이것이 내가 말하는 이유입니다. bash를 사용하지 않고 코드를 이식 가능하게 만들려고하지 마십시오. 생각보다 어렵습니다. 사용 bash
은 우리 대부분이 할 수있는 가장 휴대하기 쉬운 일입니다.
sed
실제로는 행 앞에 탭을 삽입하고 싶을 때 대체를 수행하는 데 사용할 필요가 없습니다 . 이 경우를 대체하는 것은 특히 큰 파일로 작업 할 때 인쇄하는 것보다 비용이 많이 드는 작업입니다. 정규식이 아니기 때문에 읽기도 쉽습니다.
예 : awk 사용
awk '{print "\t"$0}' $filename > temp && mv temp $filename
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:])
BSD sed 대신 perl을 사용합니다.
ct@MBA45:~$ python -c "print('\t\t\thi')" |perl -0777pe "s/\t/ /g"
hi
나는 다른 사람들이 다른 방법 (위해 적절하게이 문제를 명확히 한 생각 sed
, AWK
등). 그러나 내 bash
특정 답변 (macOS High Sierra 및 CentOS 6/7에서 테스트 됨)은 다음과 같습니다.
1) OP가 원래 제안한 것과 유사한 검색 및 바꾸기 방법을 사용하려면 perl
다음과 같이 사용 하는 것이 좋습니다 . 참고 : 정규식 괄호 앞에 백 슬래시 필요는 없습니다,이 코드 라인이 어떻게 반영 $1
보다 사용하기 더 \1
와 perl
대체 연산자 (예 : 당 펄 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