파일 앞에 텍스트를 추가하는 Unix 명령


126

텍스트 파일에 일부 문자열 데이터를 추가하는 Unix 명령이 있습니까?

다음과 같은 것 :

prepend "to be prepended" text.txt

단일 명령을 찾고 있습니까, 아니면 작은 스크립트 / 별칭 명령이 괜찮습니까?
Levon

2
모든 답변을 결합하면 아마도 가장 간단한 방법 일 것입니다.<<(echo "to be prepended") < text.txt | sponge text.txt
Sridhar Sarnobat

이 질문은 정말 많은 사람들의 창의성을 불러 일으켰습니다!
Richard Jessop

답변:


111
sed -i.old '1s;^;to be prepended;' inFile
  • -i변경 사항을 기록하고 확장이 제공되면 백업을 수행합니다. (이 경우 .old)
  • 1s;^;to be prepended;;명령 구분 기호로 사용하여 첫 번째 줄의 시작 부분을 지정된 대체 문자열로 대체합니다 .

19
명령에 대한 설명을 추가 할 수 있다면 sed의 작동에 익숙하지 않은 다른 사용자에게 도움이 될 것입니다. OP는 \n앞에 추가 한 후에 삽입 할 수 있습니다 . 그들의 필요에 따라. 깔끔한 솔루션.
Levon

예, 설명이 좋을 것입니다. inFile경로에 디렉토리를 포함 할 수 있습니까 ?
zakdances 2010 년

3
@Levon 나는 완전히 \n. 먼저 댓글을 읽어야 했어요. 제길.
chishaku

내가 갔다 그래서 내 경우에는 내가, 추가되는 말머리 줄의 끝에서 세미콜론을 갖고 싶어'1s;^;my-prepended-line\;\n;'
SamGamgee

5
'\ n'은 BSD (OSX, FreeBSD 등)가 아닌 GNU sed에서만 작동합니다. 더 이식하려면 다음을 참조하십시오. stackoverflow.com/questions/1421478/…
jwd

164
printf '%s\n%s\n' "to be prepended" "$(cat text.txt)" >text.txt

2
한 줄에 원본 텍스트 파일로! 이것은 정답입니다. 추가 새 줄 \ n echo -e "to be prepended \ n $ (cat text.txt)"> text.txt
VincentPerrin.com

32
이 솔루션에는 문제가 있습니다. "\ n"의 발생을 실제 새 줄로 변환합니다. "\ n"이 포함 된 문자열이있는 코드 파일을 앞에 추가하는 경우 문제가 있습니다.
폴 이동

1
내 파일이 있었다 git config --get-regex $arg | sed -r 's/\t{3}/\\n/g';가 변환으로이 망쳐 놨까지 \t하고 \n.
hIpPy

8
이것은 (1) 전체 파일을 메모리에로드하고 (2) 전체 파일을 단일 명령 줄 인수에 붙입니다. 간단한 일에는 좋지만 한계에주의하십시오.
jwd

2
마지막으로 시도한 결과, cat이 text.txt의 전체 내용을 덮어 쓰기 전에 읽지 못하는 정말 큰 파일에서 이것이 깨질 것이라고 믿습니다. 에코에 -e 옵션이 문제가 될 경우에는, 당신은 bash는 줄 바꿈을 인용하거나 할 수echo "to be prepended"$'\n'"$(cat text.txt)"
jbo5112

44

프로세스 대체

아무도 이것을 언급하지 않았다는 것에 놀랐습니다.

cat <(echo "before") text.txt > newfile.txt

이것은 받아 들여진 대답보다 더 자연 스럽습니다 (무언가를 인쇄하고이를 대체 명령에 연결하는 것은 사 전적으로 반 직관적입니다).

... 위에서 라이언이 말한 것을 납치 sponge하면 임시 파일이 필요하지 않습니다.

sudo apt-get install moreutils
<<(echo "to be prepended") < text.txt | sponge text.txt

편집 : Bourne Shell에서 작동하지 않는 것 같습니다. /bin/sh


Here String (zsh 전용)

here-string-사용하여 <<<다음을 수행 할 수 있습니다.

<<< "to be prepended" < text.txt | sponge text.txt

3
이 답변이 저에게 승자입니다. 내장 기능만으로 간단하고 달성 할 수 있습니다. 잘 했어!
PiersyP

1
@PiersyP 동의합니다! 이것은 많은 도움이되었습니다. Sridhar-Sarnobat에게 감사드립니다.

문제는 2 개의 파일이 아니라 1 개의 파일이 있다는 것입니다. 따라서 대답의 첫 번째 줄은 실제로 작동하지 않습니다. 마지막 줄이 작동 할 수 있습니다 (하지만 스폰지가 필요함).
VasiliNovikov 2017

1
스폰지는 무엇을합니까?
Hemanta

1
귀하의 <<(echo "to be prepended") < text.txt<<< "to be prepended" < text.txt구성은 bash에서 작동하지 않습니다. zsh가 필요합니다.
Anders Kaseorg

32

이것은 한 가지 가능성입니다.

(echo "to be prepended"; cat text.txt) > newfile.txt

중간 파일을 쉽게 다룰 수 없을 것입니다.

대안 (셸 이스케이프로 인해 번거로울 수 있음) :

sed -i '0,/^/s//to be prepended/' text.txt

전략 1)은 여기에서 가장 직관적 인 답변이라고 생각합니다. 그리고 약간의 변형 : cat <(echo "to be prepended") text.txt > newfile.txt . 생각해 보니 내 것이 관련이 있는지 확실하지 않으므로 별도의 답변을 게시했습니다.
Sridhar Sarnobat

1
첫 번째 방법은 파일 권한을 보존하지 않습니다
Xlsx

권한을 보존하는 유일한 방법은 스폰지를 사용하는 것입니다
Sridhar Sarnobat

20

이것은 출력을 형성하는 데 작동합니다. -는 에코에서 파이프를 통해 제공되는 표준 입력을 의미합니다.

echo -e "to be prepended \n another line" | cat - text.txt

파일을 다시 쓰려면 입력 파일로 다시 파이프 할 수 없으므로 임시 파일이 필요합니다.

echo "to be prepended" | cat - text.txt > text.txt.tmp
mv text.txt.tmp text.txt

2
text.txt요청한대로 파일 앞에 텍스트를 추가하지는 않지만 stdout에 표시합니다. OP에서 작동하는 경우 출력은 다른 파일로 유입 될 수 있습니다
Levon

1
이것은 확실히 "to be prepended"와 "text.txt"의 내용을 인쇄합니다. 하지만 파일 앞에 텍스트를 추가하고 싶습니다
One Two Three

1
여러 줄 텍스트가있는 경우 어떻게합니까? 개행 문자를 어떻게 넣습니까?
One Two Three

이것은 멋지지만 bash는 그것을 좋아하지 않는다 : $ echo RewriteBase / | cat-web / .htaccess> web / .htaccess cat : web / .htaccess : 입력 파일은 출력 파일입니다
괴짜 멀린

14

Adam 's 선호 답변

스펀지 를 사용하기 쉽게 만들 수 있습니다 . 이제 임시 파일을 만들고 이름을 바꿀 필요가 없습니다.

echo -e "to be prepended \n another line" | cat - text.txt | sponge text.txt

이것은 나를 위해 일하는 유일한 해결책이었습니다. 내 서버의 이름이 스폰지 밥일 정도로 재미 있어요.
Ömer An

10

입력 파일 을 교체 할 수 있는 경우 :

노트 :

  • 그렇게하면 예상치 못한 부작용이 발생할 수 있습니다. 특히 심볼릭 링크를 일반 파일로 대체하고 파일에 대한 다른 권한을 갖게되며 파일 생성 (생년월일) 날짜가 변경 될 수 있습니다.

  • sed -i, Prince John Wesley의 답변 에서와 같이 최소한 원래 권한을 복원하려고 시도하지만 다른 제한 사항도 적용됩니다.

다음 은 임시 파일을 사용 하는 간단한 대안입니다 ( shime의 솔루션 이 수행 하는 방식으로 전체 입력 파일을 메모리로 읽는 것을 방지합니다 ).

{ printf 'to be prepended'; cat text.txt; } > tmp.txt && mv tmp.txt text.txt

사용하여 그룹 명령은 ( { ...; ...; })를 사용하는 것보다 약간 더 효율적입니다 서브 쉘을 ( (...; ...)같이) 0xC0000022L의 솔루션 .

장점은 다음과 같습니다.

  • 그것은 새로운 텍스트를 직접 첫 번째 줄 앞에 추가할지 여부를 제어하기 쉽게하거나 삽입 할 것인지 등의 새로운 라인 (들) (단순히 APPEND \n받는 printf인수).

  • sed솔루션 과 달리 입력 파일이 비어 있으면 ( 0바이트) 작동합니다.


sed솔루션은 의도는 하나 개 이상의 앞에 추가하는 경우 간단하게 할 수있는 전체 라인을 (입력 파일이 비어 있지 가정) 기존 내용 :

sedi함수는 전체 행을 삽입합니다.

GNU sed :

# Prepends 'to be prepended' *followed by a newline*, i.e. inserts a new line.
# To prepend multiple lines, use '\n' as part of the text.
# -i.old creates a backup of the input file with extension '.old'
sed -i.old '1 i\to be prepended' inFile

macOS / BSD에서도 작동하는 휴대용 변형 sed:

# Prepends 'to be prepended' *followed by a newline*
# To prepend multiple lines, escape the ends of intermediate
# lines with '\'
sed -i.old -e '1 i\
to be prepended' inFile

뒤에 오는 리터럴 개행 문자 \가 필요합니다.


입력 파일 을 제자리에서 편집해야하는 경우 (모든 속성과 함께 inode 유지) :

오래된 edPOSIX 유틸리티 사용 :

노트 :

  • ed항상 입력 파일 전체 를 메모리로 먼저 읽습니다 .

첫 번째 줄에 직접 추가 하려면 (와 마찬가지로 sed입력 파일이 완전히 비어 있으면 ( 0바이트) 작동하지 않음 ) :

ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
  • -sed의 상태 메시지를 억제했습니다 .
  • 명령이 ed여러 줄의 here-document ( <<EOF\n...\nEOF), 즉 stdin을 통해 제공되는 방법에 유의 하십시오 . 기본적으로 문자열 확장 이러한 문서에서 수행됩니다 (쉘 변수는 보간됩니다). 이를 억제하려면 여는 구분 기호를 인용 하십시오 (예 :) <<'EOF'.
  • 1 첫 번째 줄을 현재 줄로 만듭니다.
  • 함수 s는 다음과 같이 현재 줄에서 정규식 기반 문자열 대체를 수행합니다 sed. 대체 텍스트에 리터럴 개행 문자를 포함 할 수 있지만\ 이스케이프 처리 .
  • w(테스트하기 위해, 대체 입력 파일에 결과 등을 기록 w으로 ,p만에 인쇄 입력 파일을 수정하지 않고, 그 결과를).

하나 이상의 전체 행앞에 추가 하려면 다음을 수행하십시오 .

와 같이, sed상기 i기능은 변함없이 텍스트에 후행 개행을 삽입 할 추가한다.

ed -s text.txt <<EOF
0 i
line 1
line 2
.
w
EOF
  • 0 i차종 0합니다 (파일의 시작) 모드 삽입 현재 라인이 시작 ( i); 줄 번호는 그렇지 않으면 1기반입니다.
  • 다음 줄은 현재 줄 앞에 삽입 할 텍스트 .이며 자체 줄 에서 끝납니다 .

7

아마도 내장 된 것은 없지만 다음과 같이 꽤 쉽게 작성할 수 있습니다.

#!/bin/bash
echo -n "$1" > /tmp/tmpfile.$$
cat "$2" >> /tmp/tmpfile.$$
mv /tmp/tmpfile.$$ "$2"

적어도 그런 건 ...


6
임시 파일 이름의 일부로 $$ (현재 PID)를 사용하는 경우 +1. 일반적인 용도로 스크립트를 만드는 경우 다른 사용자가 동시에 동일한 스크립트를 실행하여 임시 파일을 덮어 쓰는 것을 방지 할 수 있습니다.
E Brown

3
$$그러나 프로덕션 코드에는 사용 이 충분하지 않습니다 (구글 심볼릭 링크 공격). 하지만 정적 파일 이름보다 확실히 낫습니다.
tripleee

1
그냥 사용mktemp
mewa

7

경우에 따라 앞에 추가 된 텍스트는 stdin에서만 사용할 수 있습니다. 그러면이 조합이 작동합니다.

echo "to be prepended" | cat - text.txt | tee text.txt

tee출력 을 생략하려면 > /dev/null.


이 답변이 정말 마음에 듭니다. 매우 깨끗하고 명확한 방법입니다. tee의 사용은 출력을 입력 파일로 분류하려는 문제에 대한 자연스러운 해결책입니다. 또한 이름을 바꾸는 해킹이 없습니다. 새 파일을 만들지 않기 때문에 현재 가장 많이 득표 한 솔루션보다 낫습니다. 이것은 기본적으로 추가하는 대신 앞에 추가 할 때 >>에 가장 가깝습니다.
DC2

이것이 가장 좋고 깨끗한 대답입니다.
nerdoc

6
그것을 읽기 전에 tee방해하지 않는 보증이 있습니까? 나는 그렇지 않다고 생각한다. 이것은이 솔루션을 파일의 건강에 위험하게 만들 것이다. text.txtcat
Jonathan Leffler

3
@JonathanLeffler 아마 아닙니다. 테스트를 위해이 코드를 시도했습니다 : lenA=1000000; yes a | head -c $lenA > a.txt; lenB=10000; b=$(yes b | head -c $lenB); echo "$b" | cat - a.txt | tee a.txt > /dev/null. 경우 lenA1,000,000 (1MB의 파일)과 lenB(10KB 텍스트 앞에 추가) 10000, 다음 "a.txt이"가 "B"문자 20KB로 덮어 파일. 이것은 완전히 망가졌습니다. 이제 1Mb a.txt와 1Mb 텍스트를 사용하여 앞에 추가하고 tee7Gb + 파일을 생성하는 루프에 들어가면 명령을 중지해야했습니다. 따라서 큰 크기의 경우 결과를 예측할 수 없음이 분명합니다. 작은 크기에서 작동할지 여부에 대한 정보가 없습니다.
VasiliNovikov

3
개념적으로 말하면 : 이 명령은 입력 파일 이 현재 일반적으로 64KB 인 시스템의 파이프 라인 버퍼 크기보다 큰 경우 데이터 손실을 초래합니다 .
mklement0

7

해결책:

printf '%s\n%s' 'text to prepend' "$(cat file.txt)" > file.txt

확장이 없기 때문에 모든 종류의 입력에서 안전합니다. 예를 들어, 앞에 추가하려면 다음 !@#$%^&*()ugly text\n\t\n과 같이 작동합니다.

printf '%s\n%s' '!@#$%^&*()ugly text\n\t\n' "$(cat file.txt)" > file.txt

고려할 마지막 부분은 명령 대체 동안 파일 끝에서 공백을 제거하는 것입니다 "$(cat file.txt)". 이에 대한 모든 해결 방법은 비교적 복잡합니다. file.txt 끝에서 줄 바꿈을 유지 하려면 https://stackoverflow.com/a/22607352/1091436을 참조하십시오.


그것을 사랑하십시오. 휴대 성이 뛰어나며 새 파일을 생성 할 필요가 없습니다. 감사!
pyb

1
이것의 유일한 문제는의 내용이 file.txt인수 목록에 들어갈 수있는 것보다 큰 경우에 발생합니다 printf.
Jonathan Leffler

6

사용하는 또 다른 방법 sed:

sed -i.old '1 {i to be prepended
}' inFile

추가 할 줄이 여러 줄인 경우 :

sed -i.old '1 {i\ 
to be prepended\
multiline
}' inFile

왜 안 sed -i '1ito be prepended' inFile됩니까? 아니면 GNU sed에서만 허용됩니까?
사용자 알 수없는

@userunknown : standard sed에서 i명령 뒤에 백 슬래시와 줄 바꿈이오고 마지막을 제외한 각 입력 줄도 백 슬래시로 끝납니다. GNU sed는 당신이 묻는 줄에 속기를 허용하지만 sed그렇게하는 것은 GNU뿐입니다 . '
Jonathan Leffler

3

다음을 통해 테스트 파일로 시작하는 경우 Bash (Ubuntu)에서 테스트했습니다.

echo "Original Line" > test_file.txt

실행할 수 있습니다.

echo "$(echo "New Line"; cat test_file.txt)" > test_file.txt

또는 bash의 버전이 $ ()에 비해 너무 오래된 경우 백틱을 사용할 수 있습니다.

echo "`echo "New Line"; cat test_file.txt`" > test_file.txt

"test_file.txt"의 다음 내용을 수신합니다.

New Line
Original Line

중개 파일이없고 bash / echo 만 있습니다.


2
가장 좋은 대답은 다음 답변을 사용하여 파일을 회전하기 위해이 한 줄짜리를 작성했습니다. for i in $ (<file2.txt); do echo "$ (echo $ i; cat file.txt)"> file.txt; 끝난;
Aurangzeb

2

또 다른 매우 간단한 해결책은 다음과 같습니다.

    $ echo -e "string\n" $(cat file)

이것은 나를 위해 일했습니다 ... 입력 파일에서 여러 줄을 유지하려면 다음과 같이 따옴표로 묶어야합니다. echo -e "string \ n" "$ (cat ~ / file.txt) "> ~ / file.txt;
Craig Wayne

2
가지고 있지 cat따옴표로 매개 변수 확장하는 것은위한 꽤 좋은 이유입니다 downvote . 이 코드는 파일의 내용을 단어로 분할하고 각 단어를 별도의 인수로에 전달합니다 echo. 원래 인수 경계를 잃고 개행 / 탭 / 등을 잃고 원래 텍스트 \t와 같은 문자열 \n은 그대로 유지되는 대신 탭과 개행으로 대체됩니다.
Charles Duffy

1

vi / vim이 마음에 들면이 스타일이 더 좋을 것입니다.

printf '0i\n%s\n.\nwq\n' prepend-text | ed file

0
# create a file with content..
echo foo > /tmp/foo
# prepend a line containing "jim" to the file
sed -i "1s/^/jim\n/" /tmp/foo
# verify the content of the file has the new line prepened to it
cat /tmp/foo

0

함수를 정의한 다음 필요한 곳에 가져 와서 사용하는 것이 좋습니다.

prepend_to_file() { 
    file=$1
    text=$2

    if ! [[ -f $file ]] then
        touch $file
    fi

    echo "$text" | cat - $file > $file.new

    mv -f $file.new $file
}

그런 다음 다음과 같이 사용하십시오.

prepend_to_file test.txt "This is first"
prepend_to_file test.txt "This is second"

그러면 파일 내용은 다음과 같습니다.

This is second
This is first

변경 로그 업데이트 프로그램을 구현하는 데이 접근 방식을 사용하려고합니다.

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