これはおそらく複雑なソリューションです。
">>"のような単純な演算子を探していますが、前に付加する必要があります。
存在しないと思います。私は何かをしなければならないでしょう
mv myfile tmp 猫myheader tmp> myfile
何かもっと賢い?
これはおそらく複雑なソリューションです。
">>"のような単純な演算子を探していますが、前に付加する必要があります。
存在しないと思います。私は何かをしなければならないでしょう
mv myfile tmp 猫myheader tmp> myfile
何かもっと賢い?
回答:
以下のハックは、すぐに使える即答であり、多くの賛成票を集めて機能しました。その後、質問がより人気になり、時間が経つにつれ、怒り狂った人々はそれがある程度は機能したが奇妙なことが起こるか、まったく機能しなかったと報告し始めたので、しばらくの間激しく反対票を投じました。とても楽しい。
このソリューションは、システム上のファイル記述子の正確な実装を利用します。実装はnix間で大幅に異なるため、成功は完全にシステムに依存し、間違いなく移植不可能であり、漠然と重要なものについても当てにするべきではありません。
さて、それですべてが解決されました:
ファイルの別のファイル記述子を作成すると(exec 3<> yourfile
)そこに書き込む(>&3
)と、同じファイルのジレンマに対する読み取り/書き込みを克服できるようです。awkを使用して600Kファイルで動作します。ただし、「猫」を使用して同じトリックを試みると失敗します。
prependageを変数として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
これはまだ一時ファイルを使用していますが、少なくとも1行にあります。
echo "text" | cat - yourfile > /tmp/out && mv /tmp/out yourfile
クレジット:BASH:ファイルにテキスト/行を追加
-
たのcat
?
echo -n "text"
yourfile
シンボリックリンクの場合、これはあなたが望むことをしません。
echo '0a
your text here
.
w' | ed some_file
edは標準エディターです!http://www.gnu.org/fun/jokes/ed.msg.html
0r header.file
echo -e '0a\nyour text here\n.\nw' | ed some_file
John Mee:あなたのメソッドは動作することが保証されておらず、4096バイトを超えるものを付加するとおそらく失敗します(少なくともそれはgnu awkで起こりますが、他の実装でも同様の制約があると思います)。その場合に失敗するだけでなく、それ自体の出力を読み取る無限ループに入り、使用可能なすべてのスペースがいっぱいになるまでファイルが大きくなります。
自分で試してみてください:
exec 3<>myfile && awk 'BEGIN{for(i=1;i<=1100;i++)print i}{print}' myfile >&3
(警告:しばらくすると強制終了します。そうしないとファイルシステムがいっぱいになります)
さらに、そのようにファイルを編集することは非常に危険です。ファイルの編集中に何かが発生した場合(クラッシュ、ディスクがいっぱい)、一貫性のない状態でファイルが残ることがほぼ確実であるように、それは非常に悪いアドバイスです。
一時ファイルなしでは不可能ですが、ここでワンライナーを使います
{ echo foo; cat oldfile; } > newfile && mv newfile oldfile
edやperlなどの他のツールを使用して、一時ファイルなしで実行できます。
管理するコンピュータでこれが必要な場合は、パッケージ「moreutils」をインストールし、「スポンジ」を使用してください。その後、次のことができます。
cat header myfile | sponge myfile
{ echo "prepended text"; cat myfile } | sponge myfile
bash heredocを使用すると、tmpファイルの必要性を回避できます。
cat <<-EOF > myfile
$(echo this is prepended)
$(cat myfile)
EOF
これは、リダイレクト付きのcatが実行される前に、bashスクリプトが評価されるときに$(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」でのみ機能します。
this is the header
my.txtに2行で終わってしまいました。Bashを更新した後でも4.3.42(1)-release
、同じ結果が得られます。
<(...)
)のコマンドが書き込むFIFO(パイプ)を作成します。そのため、前もって完全に読み取られる保証my.txt
はなく、それがなければこの手法は機能しません。
シェルスクリプトで難しくなることをしようとするときは、「適切な」スクリプト言語(Python / Perl / Ruby / etc)でスクリプトを書き直すことを強くお勧めします。
ファイルの前に行を追加することに関しては、パイピングを介してこれを行うことはできませんcat blah.txt | grep something > blah.txt
。なぜなら、のようなことをすると、誤ってファイルをブランクにするからです。sponge
インストールできる小さなユーティリティコマンドがあります(インストールするcat blah.txt | grep something | sponge blah.txt
と、ファイルの内容がバッファされ、ファイルに書き込まれます)。これは一時ファイルに似ていますが、明示的に行う必要はありません。しかし、これは、たとえばPerlよりも「悪い」要件だと思います。
awkまたは同様の方法でそれを行う方法があるかもしれませんが、シェルスクリプトを使用する必要がある場合は、一時ファイルがはるかに簡単(/ only?)な方法だと思います。
Daniel Velkovが示唆するように、ティーを使用します。
私にとって、それはシンプルなスマートソリューションです。
{ echo foo; cat bar; } | tee bar > /dev/null
編集:これは壊れています。catとteeをファイルの先頭に追加するときの奇妙な動作を参照してください
上書きの問題の回避策は次を使用することですtee
:
cat header main | tee main > /dev/null
主にファン/シェルゴルフ用ですが、
ex -c '0r myheader|x' myfile
トリックを行い、パイプラインやリダイレクトはありません。もちろん、vi / exは実際には非対話型で使用するためのものではないため、viが短時間点滅します。
(ここでfluffleによってすでに提案されているように)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
さらに別の回避策は、sed 's / c / d /' myFileからmyFileへのリダイレクト出力で JürgenHötzelによって提案されているように、オープンファイルハンドルを使用することです。
echo cat > manipulate.txt
exec 3<manipulate.txt
# Prevent open file from being truncated:
rm manipulate.txt
sed 's/cat/dog/' <&3 > manipulate.txt
もちろん、これはすべて1行で記述できます。
「一時ファイルなし」で固定テキストを付加するcb0のソリューションのバリアント:
echo "text to prepend" | cat - file_to_be_modified | ( cat > file_to_be_modified )
再び、これはサブシェルの実行-(..)-に依存し、猫が入力と出力に同じファイルを持つことを拒否しないようにします。
注:このソリューションが気に入りました。ただし、私のMacでは元のファイルが失われています(そうすべきではないと考えられていますが)。これは、ソリューションを次のように記述することで修正できます。猫-file_to_be_modified | cat> tmp_file; mv tmp_file file_to_be_modified
警告:OPのニーズを満たすには、もう少し作業が必要です。
彼の不安にもかかわらず、@ shixilunによるsedアプローチを機能させる方法があるはずです。そこ。例えば「\ n」ので改行文字を置き換える(SED代替文字列にファイルを読み込むとき、空白逃れるためにシェルコマンドbashコマンドでなければなりませんvis
し、cat
これはOPのを解決することはできませんので、印刷不可能な文字を扱うことができますが、ない空白問題:
sed -i -e "1s/^/$(cat file_with_header.txt)/" file_to_be_prepended.txt
このSOの回答のように、シェルを維持してsedを幸せに保つために、行継続文字()を前に付けて&を続ける必要がある代替スクリプトの生の改行が原因で失敗します
sed
非グローバル検索置換コマンドの40Kのサイズ制限があるため(パターンの後に/ gが付かない)、匿名で警告されたawkの恐ろしいバッファーオーバーランの問題を回避できる可能性があります。
ソリューション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}"
しかし、その場合%
、ターゲットファイルの内容を含め、どこにもないことを確認する必要があります。これは、解釈されて結果が台無しになる可能性があるためです。
echo
より安全なオプションのようです。echo "my new line\n$(cat my/file.txt)" > my/file.txt
${new_line}
はターゲットファイルではなく、パーセントのみでした
あなたは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が置換でコードの評価を許可する場所。
@fluffleのedアプローチが一番好きです。結局のところ、ツールのコマンドラインスイッチとスクリプトエディターコマンドは、ここでは基本的に同じものです。スクリプト化されたエディターソリューションの「清潔さ」が低下しているのを見ることはありません。
以下は、メッセージをコミットするために.git/hooks/prepare-commit-msg
リポジトリ.gitmessage
内ファイルを追加するために追加された私の1行です。
echo -e "1r $PWD/.gitmessage\n.\nw" | ed -s "$1"
例.gitmessage
:
# Commit message formatting samples:
# runlevels: boot +consolekit -zfs-fuse
#
の1r
代わりに0r
実行しています。これにより、元のテンプレートのファイルの上に空の書き込み準備ができた行が残るためです。あなたの上に空の行を置かないでください.gitmessage
、あなたは2つの空の行になるでしょう。-s
edの診断情報出力を抑制します。
これを実行することに関連して、私はvim-buffsについても次のようにすると良いことを発見しました:
[core]
editor = vim -c ':normal gg'
BASHでスクリプトを作成している場合は、実際には次のように発行できます。
猫-yourfile / tmp / out && mv / tmp / out yourfile
それは実際にあなた自身があなた自身の質問に投稿した複雑な例にあります。
cat - yourfile <<<"text" > /tmp/out && mv /tmp/out yourfile
に変更することを提案しましたが、それは自分の答えでなければならないという私の答えとはかなり異なります。
私見2つのファイルmyheader
とのサイズに関係なく一貫して確実に機能するシェルソリューションはありません(1つになることはありません)myfile
。その理由は、一時ファイルを繰り返さずに(そしてシェルが一時ファイルにサイレントに再帰せずに、たとえばexec 3<>myfile
、tee
など。
あなたが探している「本当の」ソリューションはファイルシステムをいじる必要があるので、ユーザースペースでは利用できず、プラットフォームに依存します。使用myfile
中のファイルシステムポインターを、ファイルシステムポインターの現在の値に変更するように求めています。ためにmyheader
ファイルシステムのを、EOF
がmyheader
指す現在のファイルシステムアドレスへのチェーンリンクで置き換えますmyfile
。これは些細なことではなく、明らかに非スーパーユーザーによって、そしておそらくスーパーユーザーによっても行うことはできません... iノードなどで再生してください。
ただし、ループデバイスを使用すると、多かれ少なかれこれを偽造できます。たとえば、このSOスレッドを参照してください。
mktemp
ますか?後で一時ファイルをいつでもクリーンアップできます...