하나의 라이너를 파일 앞에 추가
이것은 아마도 복잡한 해결책 일 것입니다 .
">>"와 같은 간단한 연산자를 찾고 있지만 앞에 추가합니다.
그것이 존재하지 않을까 걱정됩니다. 나는 다음과 같은 일을해야 할 것이다.
mv myfile tmp 고양이 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
크레딧 : BASH : 파일 앞에 텍스트 / 줄 추가
echo '0a
your text here
.
w' | ed some_file
ed는 표준 편집기입니다! http://www.gnu.org/fun/jokes/ed.msg.html
John Mee : 메소드가 작동한다고 보장되지 않으며 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)로 스크립트를 다시 작성하는 것이 좋습니다.
As for prepending a line to a file, it's not possible to do this via piping, as when you do anything like cat blah.txt | grep something > blah.txt
, it inadvertently blanks the file. There is a small utility command called sponge
you can install (you do cat blah.txt | grep something | sponge blah.txt
and it buffers the contents of the file, then writes it to the file). It is similar to a temp file but you dont have to do that explicitly. but I would say that's a "worse" requirement than, say, Perl.
There may be a way to do it via awk, or similar, but if you have to use shell-script, I think a temp file is by far the easiest(/only?) way..
EDIT: This is broken. See Weird behavior when prepending to a file with cat and tee
The workaround to the overwrite problem is using tee
:
cat header main | tee main > /dev/null
Like Daniel Velkov suggests, use tee.
To me, that's simple smart solution:
{ echo foo; cat bar; } | tee bar > /dev/null
The one which I use. This one allows you to specify order, extra chars, etc in the way you like it:
echo -e "TEXTFIRSt\n$(< header)\n$(< my.txt)" > my.txt
P.S: only it's not working if files contains text with backslash, cause it gets interpreted as escape characters
Mostly for fun/shell golf, but
ex -c '0r myheader|x' myfile
will do the trick, and there are no pipelines or redirections. Of course, vi/ex isn't really for noninteractive use, so vi will flash up briefly.
Why not simply use the ed command (as already suggested by fluffle here)?
ed reads the whole file into memory and automatically performs an in-place file edit!
So, if your file is not that huge ...
# 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
Yet another workaround would be using open file handles as suggested by Jürgen Hötzel in Redirect output from sed 's/c/d/' myFile to 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
All this could be put on a single line, of course.
A variant on cb0's solution for "no temp file" to prepend fixed text:
echo "text to prepend" | cat - file_to_be_modified | ( cat > file_to_be_modified )
Again this relies on sub-shell execution - the (..) - to avoid the cat refusing to have the same file for input and output.
Note: Liked this solution. However, in my Mac the original file is lost (thought it shouldn't but it does). That could be fixed by writing your solution as: echo "text to prepend" | cat - file_to_be_modified | cat > tmp_file; mv tmp_file file_to_be_modified
Here's what I discovered:
echo -e "header \n$(cat file)" >file
sed -i -e '1rmyheader' -e '1{h;d}' -e '2{x;G}' myfile
WARNING: this needs a bit more work to meet the OP's needs.
There should be a way to make the sed approach by @shixilun work despite his misgivings. There must be a bash command to escape whitespace when reading a file into a sed substitute string (e.g. replace newline characters with '\n'. Shell commands vis
and cat
can deal with nonprintable characters, but not whitespace, so this won't solve the OP's problem:
sed -i -e "1s/^/$(cat file_with_header.txt)/" file_to_be_prepended.txt
fails due to the raw newlines in the substitute script, which need to be prepended with a line continuation character () and perhaps followed by an &, to keep the shell and sed happy, like this SO answer
sed
has a size limit of 40K for non-global search-replace commands (no trailing /g after the pattern) so would likely avoid the scary buffer overrun problems of awk that anonymous warned of.
sed -i -e "1s/^/new first line\n/" old_file.txt
With $( command ) you can write the output of a command into a variable. So I did it in three commands in one line and no temp file.
originalContent=$(cat targetfile) && echo "text to prepend" > targetfile && echo "$originalContent" >> targetfile
If you have a large file (few hundred kilobytes in my case) and access to python, this is much quicker than cat
pipe solutions:
python -c 'f = "filename"; t = open(f).read(); open(f, "w").write("text to prepend " + t)'
A solution with 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}"
You could also do:
printf "${new_line}\n$(cat ${target_file})" > "${target_file}"
But in that case you have to be sure there aren’t any %
anywhere, including the contents of target file, as that can be interpreted and screw up your results.
You can use perl command line:
perl -i -0777 -pe 's/^/my_header/' tmp
Where -i will create an inline replacement of the file and -0777 will slurp the whole file and make ^ match only the beginning. -pe will print all the lines
Or if my_header is a file:
perl -i -0777 -pe 's/^/`cat my_header`/e' tmp
Where the /e will allow an eval of code in the substitution.
current=`cat my_file` && echo 'my_string' > my_file && echo $current >> my_file
where "my_file" is the file to prepend "my_string" to.
I'm liking @fluffle's ed approach the best. After all, any tool's command line switches vs scripted editor commands are essentially the same thing here; not seeing a scripted editor solution "cleanliness" being any lesser or whatnot.
Here's my one-liner appended to .git/hooks/prepare-commit-msg
to prepend an in-repo .gitmessage
file to commit messages:
echo -e "1r $PWD/.gitmessage\n.\nw" | ed -s "$1"
Example .gitmessage
:
# Commit message formatting samples:
# runlevels: boot +consolekit -zfs-fuse
#
I'm doing 1r
instead of 0r
, because that will leave the empty ready-to-write line on top of the file from the original template. Don't put an empty line on top of your .gitmessage
then, you will end up with two empty lines. -s
suppresses diagnostic info output of ed.
In connection with going through this, I discovered that for vim-buffs it is also good to have:
[core]
editor = vim -c ':normal gg'
variables, 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
I think this is the cleanest variation of ed:
cat myheader | { echo '0a'; cat ; echo -e ".\nw";} | ed myfile
as a function:
function prepend() { { echo '0a'; cat ; echo -e ".\nw";} | ed $1; }
cat myheader | prepend myfile
If you're scripting in BASH, actually, you can just issue:
cat - yourfile /tmp/out && mv /tmp/out yourfile
That's actually in the Complex Example you yourself posted in your own question.
IMHO there is no shell solution (and will never be one) that would work consistently and reliably whatever the sizes of the two files myheader
and myfile
. The reason is that if you want to do that without recurring to a temporary file (and without letting the shell recur silently to a temporary file, e.g. through constructs like exec 3<>myfile
, piping to tee
, etc.
The "real" solution you are looking for needs to fiddle with the filesystem, and so it's not available in userspace and would be platform-dependent: you're asking to modify the filesystem pointer in use by myfile
to the current value of the filesystem pointer for myheader
and replace in the filesystem the EOF
of myheader
with a chained link to the current filesystem address pointed by myfile
. This is not trivial and obviously can not be done by a non-superuser, and probably not by the superuser either... Play with inodes, etc.
You can more or less fake this using loop devices, though. See for instance this SO thread.
참고URL : https://stackoverflow.com/questions/54365/shell-one-liner-to-prepend-to-a-file
'Programing' 카테고리의 다른 글
자바 : 정적 클래스? (0) | 2020.07.03 |
---|---|
반응 기본에서 버튼 비활성화 (0) | 2020.07.03 |
Apple은 이메일에서 날짜, 시간 및 주소를 어떻게 찾습니까? (0) | 2020.07.03 |
ASP.Net Web API GET에 여러 매개 변수를 어떻게 전달해야합니까? (0) | 2020.07.03 |
i- 프레임을 통한 YouTube 비디오 내장 z- 인덱스를 무시 하시겠습니까? (0) | 2020.07.03 |