하나의 라이너를 파일 앞에 추가


131

이것은 아마도 복잡한 해결책 일 것입니다 .

">>"와 같은 간단한 연산자를 찾고 있지만 앞에 추가합니다.

그것이 존재하지 않을까 걱정됩니다. 나는 다음과 같은 일을해야 할 것이다.

 mv myfile tmp
 고양이 myheader tmp> myfile

더 똑똑한 것이 있습니까?


무슨 일이야 mktemp? 나중에 임시 파일을 정리할 수 있습니다.
candu

답변:


29

아래 의 은 빠른 커프스 답변으로 많은 찬사를 받았습니다. 그런 다음 질문이 더 대중화되고 시간이 지남에 따라 분노한 사람들은 문제가 발생했지만 이상한 일이 발생하거나 전혀 작동하지 않았다고보고하기 시작했습니다. 이러한 재미.

이 솔루션은 시스템에서 파일 디스크립터의 정확한 구현을 활용하며, 구현은 nix마다 크게 다르기 때문에 성공은 전적으로 시스템에 따라 다르고 결정적으로 이식 할 수 없으며, 모호하게 중요한 것에 의존해서는 안됩니다.

이제, 그 모든 대답을 벗어난 대답은 다음과 같습니다.


파일에 대한 다른 파일 디스크립터를 exec 3<> yourfile작성하면 ( ) 파일에 쓰는 ( >&3) 동일한 파일 딜레마에 대한 읽기 / 쓰기를 극복하는 것으로 보입니다. awk가있는 600K 파일에서 작동합니다. 그러나 'cat'을 사용하여 동일한 트릭을 시도하면 실패합니다.

접두사를 awk ( -v TEXT="$text")에 변수로 전달하면 리터럴 따옴표 문제를 극복하여 'sed'로이 트릭을 수행하지 못하게합니다.

#!/bin/bash
text="Hello world
What's up?"

exec 3<> yourfile && awk -v TEXT="$text" 'BEGIN {print TEXT}{print}' yourfile >&3

3
경고 : 출력을 점검하여 첫 번째 행 외에 아무것도 변경되지 않았는지 확인하십시오. 나는이 솔루션을 사용했지만 효과가있는 것처럼 보이지만 새로운 줄이 추가 된 것으로 나타났습니다. 나는 이것이 어디에서 왔는지 이해하지 못 하므로이 솔루션에 실제로 문제가 있음을 확신 할 수는 없지만 조심하십시오.
conradlee

1
위의 bash 예제에서 큰 따옴표는 여러 줄을 추가하는 것을 보여주기 위해 캐리지 리턴에 걸쳐 있습니다. 쉘과 텍스트 편집기가 협력 중인지 확인하십시오. \ r \ n이 떠 오릅니다.
John Mee

4
주의해서 사용하십시오! 이유는 다음 설명을 참조하십시오. stackoverflow.com/questions/54365/…
Alex

3
이제 신뢰할 수 없다면 더 나은 솔루션으로 답변을 업데이트하는 것은 어떻습니까?
zakdances

해킹 유용 하고 경우에만 경우 정확히이 알려진 이유 따라서 작동하고 신중하게 제약 관찰 무엇에 따라 . 귀하의 면책 조항에도 불구하고, 귀하의 핵은 이러한 기준을 충족하지 못합니다 ( "전적으로 시스템 의존적", "이길 것 같다", "작동합니다"). 면책 조항을 진지하게 받아들이면 아무도 해킹을 사용해서는 안됩니다. 동의합니다. 그래서 우리는 무엇을 남겼습니까? 시끄러운 산만. 두 가지 옵션이 있습니다. (a) 답변을 삭제하거나 (b) 그 이유를 설명하는주의 이야기로 바꾸십시오.이 방법 일반적으로 작동 하지 않습니다 .
mklement0

102

이것은 여전히 ​​임시 파일을 사용하지만 적어도 한 줄에 있습니다.

echo "text" | cat - yourfile > /tmp/out && mv /tmp/out yourfile

크레딧 : BASH : 파일 앞에 텍스트 / 줄 추가


4
무엇을하고있어 -cat?
makbol

줄 바꿈없이 "텍스트"를 추가하는 방법이 있습니까?
chishaku

@chishakuecho -n "text"
Sparhawk

3
경고 : yourfile심볼릭 링크 인 경우 원하는 작업을 수행하지 않습니다.
dshepherd

대답이 이것과 다른가? echo "text"> / tmp / out; cat yourfile >> / tmp / out; mv / tmp / out yourfile ??
Richard


20

John Mee : 메소드가 작동한다고 보장되지 않으며 4096 바이트 이상의 물건을 추가하면 실패 할 것입니다 (적어도 gnu awk에서 발생하는 일이지만 다른 구현에는 비슷한 제약 조건이 있다고 가정합니다). 이 경우에는 실패 할뿐만 아니라 자체 출력을 읽을 수있는 무한 루프로 들어가서 사용 가능한 모든 공간이 채워질 때까지 파일이 커집니다.

직접 해보십시오.

exec 3<>myfile && awk 'BEGIN{for(i=1;i<=1100;i++)print i}{print}' myfile >&3

(경고 : 잠시 후 죽이거나 파일 시스템을 채울 것입니다)

또한 파일을 그런 식으로 편집하는 것은 매우 위험하며 파일을 편집하는 동안 (충돌, 디스크 꽉 참) 어떤 일이 발생하는 경우 파일이 일관성이없는 상태로 유지되는 것이 거의 보장되므로 매우 나쁜 조언입니다.


6
이것은 아마도 별도의 대답이 아닌 주석이어야합니다.
lkraav

10
@ Ikraav : 어쩌면 "댓글"은 매우 길고 정교하고 유용하며 어쨌든 StackOverflow의 제한된 댓글 용량과 맞지 않을 것입니다.
Hendy Irawan

18

임시 파일이 없으면 불가능하지만 여기에는 oneliner가 있습니다.

{ echo foo; cat oldfile; } > newfile && mv newfile oldfile

ed 또는 perl과 같은 다른 도구를 사용하여 임시 파일없이 수행 할 수 있습니다.


16

적어도 스크립트가 루트 권한으로 실행될 경우 mktemp 와 같은 유틸리티를 사용하여 임시 파일을 안전하게 생성 하는 것이 좋습니다 . 예를 들어 bash에서 다시 다음을 수행 할 수 있습니다.

(tmpfile=`mktemp` && { echo "prepended text" | cat - yourfile > $tmpfile && mv $tmpfile yourfile; } )

15

제어하는 컴퓨터에서이 패키지가 필요한 경우 "moreutils"패키지를 설치하고 "sponge"을 사용하십시오. 그럼 당신은 할 수 있습니다 :

cat header myfile | sponge myfile

@Vinko Vrsalovic의 답변과 결합하면 이것은 나에게 잘 작동했습니다.{ echo "prepended text"; cat myfile } | sponge myfile
Jesse Hallett

13

bash heredoc을 사용하면 tmp 파일이 필요하지 않습니다.

cat <<-EOF > myfile
  $(echo this is prepended)
  $(cat myfile)
EOF

이것은 bash 스크립트가 평가 될 때 $ (cat myfile)이 재 지정된 cat을 실행하기 전에 평가되기 때문에 작동합니다.


9

편집하려는 파일이 my.txt라고 가정

$cat my.txt    
this is the regular file

앞에 추가하려는 파일은 헤더입니다.

$ cat header
this is the header

헤더 파일에 마지막 빈 줄이 있어야합니다.
이제 앞에 붙일 수 있습니다

$cat header <(cat my.txt) > my.txt

당신은 결국

$ cat my.txt
this is the header
this is the regular file

내가 아는 한 이것은 'bash'에서만 작동합니다.


왜 이것이 작동합니까? 괄호로 인해 중간 고양이가 별도의 쉘에서 실행되고 전체 파일을 한 번에 덤프합니까?
Catskul

<(cat my.txt)는 파일 시스템 어딘가에 임시 파일을 생성한다고 생각합니다. 그런 다음 원본 파일을 수정하기 전에이 파일을 읽습니다.
cb0

누군가가 "<()"구문으로 할 수있는 일을 한 번 보여줬습니다. 그러나 나는이 방법이 어떻게 호출되는지 배운 적이 없으며 bash 맨 페이지에서 무언가를 찾을 수 없습니다. 누군가 그것에 대해 더 많이 알고 있다면 알려주십시오.
cb0

1
나를 위해 작동하지 않았다. 이유를 모릅니다. GNU bash, 버전 3.2.57 (1)-릴리스 (x86_64-apple-darwin14)를 사용하고 있으며 OS X Yosemite를 사용하고 있습니다. 나는 this is the headermy.txt에 두 줄로 끝났습니다 . Bash를 업데이트 한 후에도 4.3.42(1)-release동일한 결과를 얻습니다.
Kohányi Róbert

1
Bash는 임시 파일을 생성하지 않고 프로세스 대체 ( <(...)) 의 명령이 기록 하는 FIFO (파이프)를 생성하므로이 기술이 작동하지 않으면 전체를 읽을 수 있다는 보장my.txt 이 없습니다.
mklement0

9

쉘 스크립트에서 어려워지는 일을 시작하려고 할 때, "적절한"스크립팅 언어 (Python / Perl / Ruby / etc)로 스크립트를 다시 작성하는 것이 좋습니다.

파일에 줄을 추가하는 것과 같이 파이프를 통해이 작업을 수행 할 수는 cat blah.txt | grep something > blah.txt없습니다. sponge설치할 수 있는 작은 유틸리티 명령 이 있습니다 (그러면 cat blah.txt | grep something | sponge blah.txt파일 내용을 버퍼링 한 다음 파일에 씁니다). 임시 파일과 비슷하지만 명시 적으로 할 필요는 없습니다. 그러나 나는 그것이 Perl보다 "나쁜"요구 사항이라고 말할 것이다.

awk 또는 이와 유사한 방법으로 수행 할 수있는 방법이있을 수 있지만 쉘 스크립트를 사용해야하는 경우 임시 파일이 훨씬 쉬운 방법이라고 생각합니다.


7

Daniel Velkov가 제안한 것처럼 티를 사용하십시오.
나에게 그것은 간단한 스마트 솔루션입니다.

{ echo foo; cat bar; } | tee bar > /dev/null

7

편집 : 이것은 고장났습니다. 참조 고양이와 티와 파일에 붙이는 때 이상한 행동을

덮어 쓰기 문제에 대한 해결 방법은 다음을 사용하는 것입니다 tee.

cat header main | tee main > /dev/null

잠시 걸려요. "티 : 메인 : 기기에 남은 공간이 없습니다"로 끝납니다. main은 몇 GB이지만 원본 텍스트 파일은 몇 KB에 불과했습니다.
Marcos

3
게시 한 솔루션이 고장 나고 실제로 사용자 하드 드라이브를 가득 채운 경우 커뮤니티에 호의를 베풀고 답변을 삭제하십시오.
aioobe

1
잘못된 답변을 삭제해야한다는 지침을 알려 주시겠습니까?
Daniel Velkov

3

내가 사용하는 것. 이를 통해 원하는 방식으로 주문, 추가 문자 등을 지정할 수 있습니다.

echo -e "TEXTFIRSt\n$(< header)\n$(< my.txt)" > my.txt

추신 : 파일에 백 슬래시가있는 텍스트가 포함 된 경우에만 작동하지 않으므로 이스케이프 문자로 해석됩니다


3

대부분 재미 / 쉘 골프를위한 것이지만

ex -c '0r myheader|x' myfile

트릭을 수행하고 파이프 라인이나 리디렉션이 없습니다. 물론 vi / ex는 실제로 비 대화식 사용을위한 것이 아니므로 vi가 잠깐 동안 깜박입니다.


기존의 명령을 사용하고 간단한 방법으로 내 관점에서 가장 좋은 레시피.
Diego

2

fled에서 이미 제안한 것처럼 단순히 ed 명령을 사용하지 않는 이유는 무엇입니까?

ed는 전체 파일을 메모리로 읽고 자동으로 내부 파일 편집을 수행합니다!

따라서 파일이 그렇게 크지 않으면 ...

# cf. "Editing files with the ed text editor from scripts.",
# http://wiki.bash-hackers.org/doku.php?id=howto:edit-ed

prepend() {
   printf '%s\n' H 1i "${1}" . wq | ed -s "${2}"
}

echo 'Hello, world!' > myfile
prepend 'line to prepend' myfile

또 다른 해결 방법은 Jürgen Hötzel이 제안한대로 열린 파일 핸들을 사용하여 sed 's / c / d /'myFile에서 myFile로 출력을 리디렉션하는 것입니다.

echo cat > manipulate.txt
exec 3<manipulate.txt
# Prevent open file from being truncated:
rm manipulate.txt
sed 's/cat/dog/' <&3 > manipulate.txt

물론이 모든 것을 한 줄에 넣을 수 있습니다.


2

고정 텍스트를 앞에 추가하는 "임시 파일 없음"에 대한 cb0 솔루션의 변형 :

echo "text to prepend" | cat - file_to_be_modified | ( cat > file_to_be_modified ) 

다시 이것은 하위 쉘 실행 ((..))에 의존하여 cat이 입력 및 출력을 위해 동일한 파일을 갖는 것을 피합니다.

참고 :이 솔루션을 좋아했습니다. 그러나 내 Mac에서는 원본 파일이 손실됩니다 (생각해서는 안됩니다). 다음과 같이 솔루션을 작성하여 해결할 수 있습니다. echo "prepend to text"| 고양이-file_to_be_modified | 고양이> tmp_file; mv tmp_file 파일 _to_be_modified


1
나도 원본 파일이 손실되었습니다. 우분투 루시드.
고슴도치


2
sed -i -e '1rmyheader' -e '1{h;d}' -e '2{x;G}' myfile

2

경고 : OP의 요구를 충족시키기 위해서는 약간의 작업이 더 필요합니다.

그의 혼란에도 불구하고 @shixilun의 sed 접근법을 작동시키는 방법이 있어야합니다. 가. 쉘 명령 (A 나오지도 대체 문자열로 파일을 읽을 때 예를 들어 'N \'와 개행 문자를 대체 공백 탈출 bash는 명령이어야합니다 viscat인쇄 할 수없는 문자를 처리 할 수 있지만 공백이 해결되지 않도록 영업의 문제:

sed -i -e "1s/^/$(cat file_with_header.txt)/" file_to_be_prepended.txt

대체 스크립트의 줄 바꿈 문자로 인해 실패합니다.이 문자는 줄 연속 문자 ()가 앞에 붙어 있고 &가 뒤에 있어야 쉘과 sed를 행복하게 유지할 수 있습니다. 이 SO 답변

sed 전역 검색이 아닌 검색-대체 명령의 경우 크기 제한이 40K (패턴 뒤에 / g 없음)이므로 익명으로 경고 한 awk의 무서운 버퍼 오버런 문제를 피할 수 있습니다.


2
sed -i -e "1s/^/new first line\n/" old_file.txt

정확히 내가 찾던 것이지만 실제로 그 질문에 대한 정답은 아닙니다
masterxilo

2

$ (command) 를 사용하면 명령 의 출력을 변수에 쓸 수 있습니다. 그래서 한 줄에 세 개의 명령을 사용하고 임시 파일을 사용하지 않았습니다.

originalContent=$(cat targetfile) && echo "text to prepend" > targetfile && echo "$originalContent" >> targetfile

1

큰 파일 (필자의 경우 몇 백 킬로바이트)이 있고 파이썬에 액세스하는 경우 cat파이프 솔루션 보다 훨씬 빠릅니다 .

python -c 'f = "filename"; t = open(f).read(); open(f, "w").write("text to prepend " + t)'


1

솔루션 printf:

new_line='the line you want to add'
target_file='/file you/want to/write to'

printf "%s\n$(cat ${target_file})" "${new_line}" > "${target_file}"

당신은 또한 할 수 있습니다 :

printf "${new_line}\n$(cat ${target_file})" > "${target_file}"

그러나이 경우 %대상 파일의 내용을 포함하여 해석 할 수 없으며 결과를 망칠 수있는 곳 이 없어야 합니다.


2
printf가 형식화 옵션으로 해석하는 대상 파일에 무언가가 있으면 이것이 터져서 파일이 잘리는 것처럼 보입니다.
Alan H.

echo더 안전한 옵션처럼 보입니다. echo "my new line\n$(cat my/file.txt)" > my/file.txt
Alan H.

@AlanH. 나는 대답의 위험에 대해 경고합니다.
user137369

실제로 ${new_line}타겟 파일이 아닌의 퍼센트에 대해서만 경고했습니다
Alan H.

좀 더 명확하게 말씀해 주시겠습니까? 정말 큰주의 IMO입니다. "어디서나"는 이것을 명확하게하지 않습니다.
Alan H.

1

perl 명령 행을 사용할 수 있습니다.

perl -i -0777 -pe 's/^/my_header/' tmp

여기서 -i는 파일의 인라인 대체를 작성하고 -0777은 전체 파일을 처리하고 ^는 시작과 만 일치시킵니다. -pe는 모든 줄을 인쇄합니다

또는 my_header가 파일 인 경우 :

perl -i -0777 -pe 's/^/`cat my_header`/e' tmp

/ e가 대체에서 코드의 평가를 허용하는 곳.


0
current=`cat my_file` && echo 'my_string' > my_file && echo $current >> my_file

여기서 "my_file"은 "my_string"앞에 붙일 파일입니다.


0

@fluffle의 ed 접근법을 좋아합니다. 최고. 결국 도구의 명령 행 스위치와 스크립트 편집기 명령은 본질적으로 동일합니다. 스크립팅 된 편집기 솔루션 "청결성"이 더 적거나 그렇지 않은 것을 보지 못했습니다.

메시지를 커밋하기 위해 .git/hooks/prepare-commit-msgin-repo .gitmessage파일을 추가하기 위해 하나의 라이너가 추가되었습니다 .

echo -e "1r $PWD/.gitmessage\n.\nw" | ed -s "$1"

.gitmessage:

# Commit message formatting samples:
#       runlevels: boot +consolekit -zfs-fuse
#

원본 템플릿의 파일 위에 비어있는 쓰기 준비가 된 줄을 남겨두기 때문에 1r대신에 하고 0r있습니다. 빈 줄을 그 위에 두지 마십시오 .gitmessage. 빈 줄 두 개가 생깁니다.-sed의 진단 정보 출력을 억제합니다.

이 겪고과 관련하여, 나는 발견 VIM-좋아하는 분들을 위해도가 좋은 것을 :

[core]
        editor = vim -c ':normal gg'

0

변수, ftw?

NEWFILE=$(echo deb http://mirror.csesoc.unsw.edu.au/ubuntu/ $(lsb_release -cs) main universe restricted multiverse && cat /etc/apt/sources.list)
echo "$NEWFILE" | sudo tee /etc/apt/sources.list

0

나는 이것이 ed의 가장 깨끗한 변형이라고 생각합니다.

cat myheader | { echo '0a'; cat ; echo -e ".\nw";} | ed myfile

함수로서 :

function prepend() { { echo '0a'; cat ; echo -e ".\nw";} | ed $1; }

cat myheader | prepend myfile

0

BASH로 스크립팅하는 경우 실제로 다음을 발행 할 수 있습니다.

고양이-yourfile / tmp / out && mv / tmp / out yourfile

그것은 실제로 당신이 당신 자신의 질문에 게시 한 복잡한 예에 있습니다.


편집자는 이것을으로 변경하도록 제안 cat - yourfile <<<"text" > /tmp/out && mv /tmp/out yourfile했지만 내 답변과는 완전히 다르므로 자체 답변이어야합니다.
팀 케네디

0

이럴 일관되고 안정적으로 어떤 두 파일의 크기 일 것이라고이 더 쉘 솔루션입니다 (결코 하나가 될 수 없습니다) myheadermyfile. 그 이유는 임시 파일을 되풀이하지 않고 (예를 들어 exec 3<>myfile, 파이핑 대상 등과 같은 구문을 통해) 셸이 임시 파일로 자동 반복되지 않도록 하기 위해서입니다 tee.

찾고있는 "실제"솔루션은 파일 시스템과 함께 작동해야하므로 사용자 영역에서 사용할 수 없으며 플랫폼에 따라 다릅니다. 사용중인 파일 시스템 포인터를 파일 시스템 포인터 myfile의 현재 값으로 수정하도록 요청하고 있습니다. 대한 myheader과하면 파일 시스템에서 대체 EOFmyheader가 가리키는 현재의 파일 시스템 주소로 체인으로 연결된 링크 myfile. 이것은 사소하지 않으며 분명히 비 수퍼 유저가 수행 할 수 없으며 아마도 수퍼 유저도 수행 할 수 없습니다. inode와 함께 플레이하십시오.

그러나 루프 장치를 사용하여 다소 위조 할 수 있습니다. 예를 들어이 SO 스레드를 참조하십시오 .

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