1つのライナーをシェルでファイルに付加する


131

これはおそらく複雑なソリューションです。

">>"のような単純な演算子を探していますが、前に付加する必要があります。

存在しないと思います。私は何かをしなければならないでしょう

 mv myfile tmp
 猫myheader tmp> myfile

何かもっと賢い?


何が問題になっていmktempますか?後で一時ファイルをいつでもクリーンアップできます...
candu

回答:


29

以下のハックは、すぐに使える即答であり、多くの賛成票を集めて機能しました。その後、質問がより人気になり、時間が経つにつれ、怒り狂った人々はそれがある程度は機能したが奇妙なことが起こるか、まったく機能しなかったと報告し始めたので、しばらくの間激しく反対票を投じました。とても楽しい。

このソリューションは、システム上のファイル記述子の正確な実装を利用します。実装は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

3
警告:出力をチェックして、最初の行以外は何も変更されていないことを確認します。私はこのソリューションを使用しましたが、機能しているように見えましたが、いくつかの新しい行が追加されているように見えました。これらの原因がわからないので、このソリューションに本当に問題があるかどうかはわかりませんが、注意してください。
conradlee

1
上記のbashの例では、複数行を前に付けることを示すために、二重引用符がキャリッジリターンにまたがっていることに注意してください。シェルとテキストエディタが連携していることを確認してください。\ r \ n頭に浮かぶ。
John Mee

4
これは注意して使用してください!:なぜについては、以下のコメントを参照してくださいstackoverflow.com/questions/54365/...
アレックス

3
現在、信頼性が低い場合は、より良いソリューションで回答を更新してみませんか?
ザクダンス2013年

ハックは便利である場合にのみ、それは正確に知られている理由は、それゆえ、それが動作し、慎重に制約を観察したものを下に。あなたの免責事項にもかかわらず、あなたのハックはこれらの基準を満たしていません(「完全にシステムに依存する」、「克服するように思われる」、「私のために働く」)私たちがあなたの免責事項を真剣に受け止めるなら、誰もあなたのハックを使うべきではありません -そして私は同意します。では、何が残っているのでしょうか。騒々しい気晴らし。私は2つのオプションを参照してください。()あなたの答え、または(b)の理由を説明する訓話にそれを回す削除-このアプローチは-それがされるように誘惑することはできません動作し、一般的に
mklement0 2017年

102

これはまだ一時ファイルを使用していますが、少なくとも1行にあります。

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

クレジット:BASH:ファイルにテキスト/行を追加


4
何をし-たのcat
makbol 2015

後に改行なしで「テキスト」を追加する方法はありますか?
chishaku

@chishakuecho -n "text"
Sparhawk

3
警告:yourfileシンボリックリンクの場合、これはあなたが望むことをしません。
dshepherd 2017年

答えはこれとは異なります: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、2011

10
@Ikraav:多分、しかし「コメント」は非常に長くて手の込んだ(そして有用な)ものであり、見た目が悪く、おそらくStackOverflowの限られたコメント容量には適合しません。
ヘンディイラワン

18

一時ファイルなしでは不可能ですが、ここでワンライナーを使います

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

edやperlなどの他のツールを使用して、一時ファイルなしで実行できます。


16

少なくともスクリプトがroot権限で実行される場合は、mktempのようなユーティリティを使用して一時ファイルを安全に生成することはしばしば良い考えであることは注目に値するかもしれません。たとえば、次のことができます(これもbashで)。

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

15

管理するコンピュータでこれが必要な場合は、パッケージ「moreutils」をインストールし、「スポンジ」を使用してください。その後、次のことができます。

cat header myfile | sponge myfile

@Vinko Vrsalovicの答えと組み合わせるとこれは私のためにうまく働いていた:{ echo "prepended text"; cat myfile } | sponge myfile
ジェシーハレット

13

bash heredocを使用すると、tmpファイルの必要性を回避できます。

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

これは、リダイレクト付きのcatが実行される前に、bashスクリプトが評価されるときに$(cat myfile)が評価されるため機能します。


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 2010年

誰かが「<()」構文で何ができるかを教えてくれました。しかし、私はこのメソッドがどのように呼び出されるかを学んだことがないし、bashのマンページで何かを見つけることもできませんでした。誰かがそれについてもっと知っているなら、私に知らせてください。
cb0 2010年

1
私のために働いていませんでした。理由がわからない。私はGNU bash、バージョン3.2.57(1)-release(x86_64-apple-darwin14)を使用していますが、OS X Yosemiteを使用しています。私はthis is the headermy.txtに2行で終わってしまいました。Bashを更新した後でも4.3.42(1)-release、同じ結果が得られます。
Kohányiロバート

1
Bashは一時ファイルを作成せず、プロセス置換(<(...))のコマンドが書き込むFIFO(パイプ)を作成します。そのため、前もって完全に読み取られる保証my.txtはなく、それがなければこの手法は機能しません。
mklement0 2017年

9

シェルスクリプトで難しくなることをしようとするときは、「適切な」スクリプト言語(Python / Perl / Ruby / etc)でスクリプトを書き直すことを強くお勧めします。

ファイルの前に行を追加することに関しては、パイピングを介してこれを行うことはできませんcat blah.txt | grep something > blah.txt。なぜなら、のようなことをすると、誤ってファイルをブランクにするからです。spongeインストールできる小さなユーティリティコマンドがあります(インストールするcat blah.txt | grep something | sponge blah.txtと、ファイルの内容がバッファされ、ファイルに書き込まれます)。これは一時ファイルに似ていますが、明示的に行う必要はありません。しかし、これは、たとえばPerlよりも「悪い」要件だと思います。

awkまたは同様の方法でそれを行う方法があるかもしれませんが、シェルスクリプトを使用する必要がある場合は、一時ファイルがはるかに簡単(/ only?)な方法だと思います。


7

Daniel Velkovが示唆するように、ティーを使用します。
私にとって、それはシンプルなスマートソリューションです。

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

7

編集:これは壊れています。catとteeをファイルの先頭に追加するときの奇妙な動作を参照してください

上書きの問題の回避策は次を使用することですtee

cat header main | tee main > /dev/null

しばらく吊り下げました。「tee:main:デバイスにスペースが残っていません」で終わる。メインは数GBでしたが、元のテキストファイルは両方とも数KBしかありませんでした。
Marcos

3
あなたが投稿したソリューションが壊れている場合(そして実際にユーザーのハードドライブがいっぱいになる場合)は、コミュニティに賛成して回答を削除してください。
aioobe 2014

1
間違った答えは削除するべきだというガイドラインを教えていただけますか?
Daniel Velkov 2014

3

私が使っているもの。これにより、順序、追加の文字などを好きなように指定できます。

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

PS:ファイルにバックスラッシュ付きのテキストが含まれている場合のみ機能しません。エスケープ文字として解釈されます。


3

主にファン/シェルゴルフ用ですが、

ex -c '0r myheader|x' myfile

トリックを行い、パイプラインやリダイレクトはありません。もちろん、vi / exは実際には非対話型で使用するためのものではないため、viが短時間点滅します。


現在のコマンドを使用し、それを簡単な方法で行うため、私の観点からの最高のレシピ。
ディエゴ

2

(ここで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行で記述できます。


2

「一時ファイルなし」で固定テキストを付加する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


1
私も元のファイルが失われているのを見つけました。Ubuntu Lucid。
ハリネズミ



2

警告: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の恐ろしいバッファーオーバーランの問題を回避できる可能性があります。


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

まさに私が探していたものですが、確かに質問に対する正しい答えではありません
masterxilo

2

$(コマンド)は、変数にコマンドの出力を書き込むことができます。だから私は1行に3つのコマンドでそれを行い、一時ファイルはありませんでした。

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

1

大きなファイル(私の場合は数百キロバイト)とpythonへのアクセスがある場合、これは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がフォーマットオプションとして解釈する対象ファイルに何かがある場合、これは爆発する(そしてファイルを切り捨てる!)ようです。
アランH.

echoより安全なオプションのようです。echo "my new line\n$(cat my/file.txt)" > my/file.txt
アランH.

@AlanH。答えの危険を警告します。
user137369

実際、警告を出したの${new_line}はターゲットファイルではなく、パーセントのみでした
アランH.

もっと明確にしていただけませんか?これは非常に大きな注意点のIMOです。「どこでも」では、これはあまり明確になりません。
アラン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-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つの空の行になるでしょう。-sedの診断情報出力を抑制します。

これを実行することに関連して、私はvim-buffsについても次のようにすると良いことを発見しました:

[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に変更することを提案しましたが、それは自分の答えでなければならないという私の答えとはかなり異なります。
Tim Kennedy

0

私見2つのファイルmyheaderとのサイズに関係なく一貫して確実に機能するシェルソリューションはありません(1つになることはありません)myfile。その理由は、一時ファイルを繰り返さずに(そしてシェルが一時ファイルにサイレントに再帰せずに、たとえばexec 3<>myfileteeなど。

あなたが探している「本当の」ソリューションはファイルシステムをいじる必要があるので、ユーザースペースでは利用できず、プラットフォームに依存します。使用myfile中のファイルシステムポインターを、ファイルシステムポインターの現在の値に変更するように求めています。ためにmyheaderファイルシステムのを、EOFmyheader指す現在のファイルシステムアドレスへのチェーンリンクで置き換えますmyfile。これは些細なことではなく、明らかに非スーパーユーザーによって、そしておそらくスーパーユーザーによっても行うことはできません... iノードなどで再生してください。

ただし、ループデバイスを使用すると、多かれ少なかれこれを偽造できます。たとえば、このSOスレッドを参照してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.