문제

이것은 아마도 복잡한 솔루션.

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

존재하지 않는 것 같습니다.나는 다음과 같은 일을해야 할 것이다

 mv myfile tmp
 cat myheader tmp > myfile

더 똑똑한 것이 있나요?

도움이 되었습니까?

해결책

그만큼 마구 자르기 아래는 효과가 있었고 많은 찬성표를 받은 빠른 즉석 답변이었습니다.그러다가 질문이 더 대중화되고 시간이 더 흐르면서 분노한 사람들은 그것이 효과가 있었지만 이상한 일이 일어날 수 있거나 전혀 효과가 없었을 수 있다고 보고하기 시작했습니다. 그래서 한동안 격렬하게 반대표를 받았습니다.이러한 재미.

이 솔루션은 시스템에서 파일 설명자의 정확한 구현을 활용하며 구현은 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

다른 팁

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

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

신용 거래: 세게 때리다:파일 앞에 텍스트/줄 추가

echo '0a
your text here
.
w' | ed some_file

ed는 표준 편집기입니다! http://www.gnu.org/fun/jokes/ed.msg.html

존 미:귀하의 방법은 작동이 보장되지 않으며 4096바이트 이상의 항목을 앞에 추가하면 아마도 실패할 것입니다(적어도 gnu awk에서는 그런 일이 발생하지만 다른 구현에도 비슷한 제약이 있을 것이라고 가정합니다).이 경우 실패할 뿐만 아니라 자체 출력을 읽는 무한 루프에 들어가므로 사용 가능한 모든 공간이 채워질 때까지 파일이 커집니다.

직접 시도해 보세요.

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

(경고:잠시 후 종료하지 않으면 파일 시스템이 채워집니다)

더욱이, 그런 식으로 파일을 편집하는 것은 매우 위험하고 매우 나쁜 조언입니다. 마치 파일을 편집하는 동안 어떤 일이 발생하면(충돌, 디스크 가득 참) 파일이 일관성 없는 상태로 남게 될 것이 거의 확실하기 때문입니다.

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

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

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

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

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

제어하는 컴퓨터에 이 기능이 필요한 경우 "moreutils" 패키지를 설치하고 "sponge"를 사용하세요.그러면 다음을 수행할 수 있습니다.

cat header myfile | sponge myfile

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

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

이는 bash 스크립트가 평가될 때 리디렉션이 포함된 cat이 실행되기 전에 $(cat myfile)이 평가되기 때문에 작동합니다.

편집하려는 파일이 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'에서만 작동합니다.

쉘 스크립트에서 어려워지는 작업을 시도하기 시작하면 "적절한" 스크립팅 언어(Python/Perl/Ruby/etc)로 스크립트를 다시 작성하는 방법을 고려해 볼 것을 강력히 제안합니다.

파일 앞에 한 줄을 추가하는 경우 다음과 같은 작업을 수행할 때처럼 파이핑을 통해 이 작업을 수행하는 것은 불가능합니다. cat blah.txt | grep something > blah.txt, 실수로 파일을 비웁니다.다음과 같은 작은 유틸리티 명령이 있습니다. sponge 당신은 설치할 수 있습니다 (당신은 cat blah.txt | grep something | sponge blah.txt 파일의 내용을 버퍼링한 다음 이를 파일에 씁니다.이는 임시 파일과 유사하지만 명시적으로 수행할 필요는 없습니다.하지만 나는 이것이 Perl보다 "더 나쁜" 요구 사항이라고 말하고 싶습니다.

awk 등을 통해 할 수 있는 방법이 있을 수 있지만 쉘 스크립트를 사용해야 한다면 임시 파일이 가장 쉬운(/유일한?) 방법이라고 생각합니다.

편집하다:이것은 깨졌습니다.보다 고양이와 티가 있는 파일 앞에 추가할 때 이상한 동작

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

cat header main | tee main > /dev/null

Daniel Velkov가 제안한 것처럼 티를 사용하세요.
나에게 그것은 간단하고 현명한 솔루션입니다.

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

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

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

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

주로 재미/쉘 골프를 위한 것이지만

ex -c '0r myheader|x' myfile

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

단순히 ed 명령(여기서 fluffle이 이미 제안한 대로)을 사용하면 어떨까요?

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

또 다른 해결 방법은 Jurgen 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

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

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

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

이는 고양이가 입력과 출력에 동일한 파일을 사용하는 것을 거부하는 것을 방지하기 위해 하위 쉘 실행((..))에 의존합니다.

메모:이 솔루션이 마음에 들었습니다.그러나 내 Mac에서는 원본 파일이 손실되었습니다(그렇지 않아야 한다고 생각했지만 실제로 발생했습니다).솔루션을 다음과 같이 작성하면 문제가 해결될 수 있습니다.echo "prepend to prepend"| 고양이 -file_to_be_modified | 고양이> tmp_file;mv tmp_file file_to_be_modified

제가 발견한 내용은 다음과 같습니다.

echo -e "header \n$(cat file)" >file
sed -i -e '1rmyheader' -e '1{h;d}' -e '2{x;G}' myfile

경고:OP의 요구 사항을 충족하려면 조금 더 많은 작업이 필요합니다.

그의 불안에도 불구하고 @shixilun이 작동하도록 sed 접근 방식을 만들 수 있는 방법이 있어야 합니다.파일을 sed 대체 문자열로 읽을 때 공백을 이스케이프 처리하는 bash 명령이 있어야 합니다(예:개행 문자를 ' '으로 바꿉니다.쉘 명령 vis 그리고 cat 인쇄할 수 없는 문자는 처리할 수 있지만 공백은 처리할 수 없으므로 OP의 문제는 해결되지 않습니다.

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

쉘과 sed를 행복하게 유지하려면 줄 연속 문자()를 앞에 추가하고 &를 뒤에 붙여야 하는 대체 스크립트의 원시 개행 문자로 인해 실패합니다. 이 SO 답변

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

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

와 함께 $( 명령 ) 명령의 출력을 변수에 쓸 수 있습니다.그래서 임시 파일 없이 한 줄에 세 개의 명령으로 작업을 수행했습니다.

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

큰 파일(내 경우에는 수백 킬로바이트)이 있고 Python에 액세스할 수 있는 경우 이는 다음보다 훨씬 빠릅니다. cat 파이프 솔루션:

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

솔루션 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}"

하지만 그런 경우에는 아무 것도 없는지 확인해야 합니다. % 대상 파일의 내용을 포함하여 어디에서나 해석되어 결과를 망칠 수 있습니다.

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는 대체 코드 평가를 허용합니다.

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

여기서 "my_file"은 "my_string" 앞에 추가할 파일입니다.

나는 좋아한다 @플러플의 에드 접근하다 최고.결국 모든 도구의 명령줄 스위치와 스크립트 편집기 명령은 본질적으로 동일합니다.스크립트 편집기 솔루션의 "청결성"이 그 이하이거나 전혀 다른 것으로 보이지 않습니다.

여기에 내 한 줄의 내용이 첨부되어 있습니다. .git/hooks/prepare-commit-msg 저장소에 미리 추가하기 .gitmessage 메시지를 커밋할 파일:

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

.gitmessage:

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

나는 일을 해요 1r 대신에 0r, 원본 템플릿의 파일 상단에 즉시 쓸 수 있는 빈 줄이 남게 되기 때문입니다.당신의 위에 빈 줄을 두지 마십시오 .gitmessage 그러면 빈 줄 두 개가 남게 됩니다. -s ed의 진단 정보 출력을 억제합니다.

이 일을 겪으면서 나는 발견 vim-buffs의 경우 다음을 갖는 것도 좋습니다.

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

변수야, 뭐야?

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

나는 이것이 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

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

cat - yourfile  /tmp/out && mv /tmp/out yourfile

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

IMHO 두 파일의 크기에 관계없이 일관되고 안정적으로 작동하는 셸 솔루션은 없습니다(그리고 앞으로도 없을 것입니다). myheader 그리고 myfile.그 이유는 임시 파일을 반복하지 않고(그리고 쉘이 자동으로 임시 파일로 반복되도록 하지 않고) 그렇게 하려는 경우입니다.다음과 같은 구성을 통해 exec 3<>myfile, 배관 tee, 등.

당신이 찾고 있는 "실제" 솔루션은 파일 시스템을 조작해야 하므로 사용자 공간에서는 사용할 수 없으며 플랫폼에 따라 다릅니다.사용 중인 파일 시스템 포인터를 수정하려고 합니다. myfile 파일 시스템 포인터의 현재 값 myheader 파일 시스템에서 EOF ~의 myheader 다음이 가리키는 현재 파일 시스템 주소에 대한 체인 링크가 있습니다. myfile.이것은 사소한 일이 아니며 분명히 슈퍼유저가 아닌 사람은 수행할 수 없으며 아마도 슈퍼유저도 수행할 수 없습니다.inode 등을 가지고 놀아보세요.

그러나 루프 장치를 사용하면 이를 어느 정도 가짜로 만들 수 있습니다.예를 들어 참조 이 SO 스레드.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top