質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • sh

    291questions

    shは、UNIX系OSのシェル操作の1つであり、最も基本的なシェルのことです。

shellでファイルの先頭に文字列(改行入り)を挿入したい

解決済

回答 8

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 10K+

jollyjoester

Swift愛好会 会長

shellでファイルの先頭に例えば下記のような文字列(改行入り)を挿入したいです。
環境はMac & zshです。

Title

message : hogehoge

sed等で簡単にできるかなと思ったのですが意外と手こずり、結局以下のような感じになってます(´・ω・`)
もっとスマートな方法があると思うのですが、シェル力がなさ過ぎてこれが限界でした。

# sample.txtというファイルの先頭に文字列を追加したい場合
# 元のファイルを複製
cp -r sample.txt sample.txt.old

# 追加したい文字列をファイルに出力
echo -e "Title\\n\\nmessage : hogehoge\\n" > add.txt

# ファイルをくっつけて元のファイルを更新
cat add.txt sample.txt.old > sample.txt

# いらんファイル消す
rm -rf add.txt sample.txt.old

もっといい方法をご存知の方、どうぞご教授お願いしますm(_ _)m

[追記]
最初sedでやろうとしたときはこんな感じでやりました。
(MacのsedはBSD系ということで-iの後ろの引数にバックアップファイルの拡張子を入れないといけないのですが、バックアップファイルはいらないので""にしてます。)
$ sed -i "" "1iTitle\n\nmessage : hogehoge\n" sample.txt
sed: 1: "1iTitle\n\nmessage : ho ...": command i expects \ followed by text
そしたらこんなエラーになってしまい、よくわからなかったので上記の回避策になった次第です。

[追記2]
Mac(BSD)のsedのiコマンドで改行をうまく扱えないのはバグのようでした。2005年のバグが2009年時点でも未解決とコメントされていますが、現在でも未解決のようですね。
http://www.linuxquestions.org/questions/programming-9/sed-error-command-c-expects-%5C-followed-by-text-under-os-x-but-works-in-linux-730997/

[追記3]
多くの皆様に回答していただき、大変感謝です!
どの回答も素晴らしく大変勉強になりました。
ベストアンサーを選ぶのが苦しかったのですが、shの範囲内でシンプルな書き方のできるedコマンドとsedのsコマンドの回答をベストアンサーにさせていただきました。
個人的にはngyukiさんのsedを使わない別解が好きです^^
実際の現場ではperlの回答を採用することになりそうですw
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 8

checkベストアンサー

+5

ファイルを直接書き換えるなら、いまではあまり一般的では無いですが ed コマンドがあります(本来は普通のエディタ)。
裏で新規ファイルを作らずに元のファイルに上書きします。

cat <<EOS | ed sample.txt
0a
Title

message : hogehoge

.
wq
EOS
補足:
もし、ed が無ければ ex でもいいです。

追記:
いろいろ試しましたが、BSDのsedだとコマンドラインでのiコマンドは無理そうです。
iコマンドを使うには、別途sedスクリプトを書いたファイルを作って、sed -f するしかなさそうです。

iコマンドでなくsコマンドを使ったpi-chanさんの回答をBSD用に書き直すと、
sed  -i "" -e $'1s/^/Title\\\n\\\nmessage : hogehoge\\\n/' sample.txt

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/07/18 22:50

    ありがとうございます!これもいいですね。edコマンドもうちょい調べてみます!

    キャンセル

  • 2015/07/19 16:32

    回答追記ありがとうございます!
    sコマンドでのsed、期待通りの動作です!

    キャンセル

+4

こういうことでしょうか?

sed -i "1iTitle\n\nmessage : hogehoge\n" sample.txt

1i で、1行目に挿入、です。

(CentOS + bash で試しているので Mac + zsh で動かなかったらごめんなさい)


sed on OSX insert at a certain line

Mac の sed はかなり異なっているようです。。。

  • i の後ろにバックスペースと改行が必要
  • i で改行を挿入できない(ので x と p で代替)

sed -i '' -e $'1{\ni\\\nTitle\nx\np\np\nx\ni\\\nmessage : hogehoge\n}' sample.txt

下記と同じです。

sed -i '' '1{
  i\
  Title
  x
  p
  p
  x
  i\
  message : hogehoge
}
' sample.txt

(Mac + bash で試しているので Mac + zsh で動かなかったらごめんなさい)


投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/07/17 21:00

    -i オプションについての説明もあった方が良いでしょうね。出力ファイルの作成とリネーム(-cも併用するとリネームで無くコピー)を裏で行って、あたかもファイルを上書きしたかのごとくの結果になります。

    キャンセル

  • 2015/07/18 22:47

    そうなんです!
    最初この方法でいけるかなと思ったのですがMacのsedがBSD系のsedらしくダメだったんです(´;ω;`)
    (質問に書いといた方がよかったですね。追記します。)

    キャンセル

  • 2015/07/18 23:05

    BSD系のsedコマンドは、iオプションのパラメータを省略できなそうなので、
    -i ''
    と書くのだそうです。下記に説明されていました。

    > http://qiita.com/catfist/items/1156ae0c7875f61417ee

    キャンセル

  • 2015/07/18 23:51

    ありがとうございます!
    それを試した先にさらなるエラーが(泣)
    (状態を質問に追記しました。)

    キャンセル

  • 2015/07/19 16:41

    回答追記ありがとうございます!
    なるほど、command i expects \ followed by textエラーはそういうことだったのですね。。。
    あとすみませんxとpのくだりが理解できてないのですがなぜここはxとpなのでしょうか?m(_ _)m

    キャンセル

  • 2015/07/19 20:26

    i で改行を挿入することができなかったので、その代わりに x と p を使っています。

    最初の x でパターンスペースを空にして、続きの2個の p でパターンスペースを出力、次の x でパターンスペースを元に戻しています。

    キャンセル

  • 2015/07/19 20:36

    なるほど!理解しました。(理解しましたが使いこなせる気がしない^^;;;)
    もっと精進しますm(_ _)m
    貴重な回答ありがとうございます!

    キャンセル

+1

# 追加したい文字列をファイルに出力
# ファイルをくっつけて元のファイルを更新
の 2つのプロセスは
echo -e "Title\\n\\nmessage : hogehoge\\n"|cat - sample.txt.old > sample.txt
と一発でできます。

上書き更新自体は、お気づきの通り、難しい処理なので 一時ファイル無しで、ファイルを上書き更新するシェルスクリプト のような方法しかないのではないでしょうか。

 &&  等を用いれば、行数を削ることはできますが、実質、複製・上書き・削除の3つは必要であると思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/07/18 22:43

    回答ありがとうございます!
    ハイフンで標準入出力になるってこと知らなかったので勉強になりました。

    キャンセル

+1

sed を使わない別解です。

rm -f sample.txt を挟むことで cat - sample.txt と cat > sample.txt を別のファイル(別の i-node)にしています。

echo -e "Title\n\nmessage : hogehoge\n" | cat - sample.txt | (rm -f sample.txt ; cat > sample.txt )

これ・・cat が sample.txt を開くより先に rm が sample.txt を削除するとダメそうなので、次のように sample.txt はシェルに開かせたほうがいいかもしれません。

cat <(echo -e "Title\n\nmessage : hogehoge\n") - < sample.txt | (rm -f sample.txt ; cat > sample.txt)

これなら sample.txt は cat が開始するより先にシェルが開くので確実だと思います。

(CentOS + bash で試しているので Mac + zsh で動かなかったらごめんなさい)


投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/07/18 22:49

    Macでもいけました!
    これはいい感じですね(`・ω・´)

    キャンセル

+1

こんな感じで如何でしょうか?

perl -i -0777pe 's/^/Title\n\nmessage : hogehoge\n/' sample.txt

行の区切り文字を指定するオプション「0」のパラメータに、文字の割り当てがないコード「777」を指定すると、ファイルを行単位ではなく一括で読み込み処理をします。

「i」オプションの挙動はMacでも変わりません。

巨大ファイルに対しては使用できませんが、ファイルの先頭に文字列を挿入する簡便法として有用かと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/07/19 16:26

    perl!そうだったPerl使ったことないんでMacで普通にperl使えるの忘れてました。。。
    期待通りの動作です^^/

    キャンセル

+1

perl なら下記のようにすると良いかと思います。

perl -i -pe 's/^/Title\n\nmessage : hogehoge\n/ if $. == 1' sample.txt

-i は sed の -i と同じ。
-p は perl を sed と同じように動かすためのオプションです。
-e はその後に perl スクリプトが続きます。

スクリプトの $. は読んだファイルの行番号です。後置if で1行目だけ置換しています。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/07/19 16:28

    こちらもperlという選択肢を気づかせてくれてありがとうございます!
    動作も期待通りです^^/

    キャンセル

0

参考情報
- Tool for adding license headers to source files?  http://stackoverflow.com/questions/151677/

- How do I insert a line at the top of a text file using the command line?  http://askubuntu.com/questions/151674/

google で "sh file insert header" を検索した結果からの抜粋です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/07/18 23:03

    情報ありがとうございます!
    いろいろ試してみたいと思います(^^/
    が、Mac上でshを使った場合だとあんまりなさそうですね(´・ω・`)

    キャンセル

0

1行目だけ置換するというアイデアを拝借すると、sed ならこのように書けますね。

sed -i"" -e '1s/^/Title\n\nmessage : hogehoge\n/' sample.txt

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/07/19 16:24

    おお!-iと""をくっつけるんですか!!
    いけたと思ったんですが改行がnになっちゃいました。。。\\nにしてみてもダメっすね。。。

    キャンセル

  • 2015/07/19 20:19

    勘違いだったら申し訳ありませんが、ひょっとして、スクリプト部分

    ```
    1s/^/Title\n\nmessage : hogehoge\n/
    ```

    をダブルクォート `"` で括っていませんか?
    そこはシングルクォート `'` で括らないとダメですよ。

    自分のMacで確認すると想定通りの結果になっていますが…

    ```
    $ cat sample.txt
    test1
    test2
    test3
    $
    $ sed -i"" -e '1s/^/Title\n\nmessage : hogehoge\n/' sample.txt
    $
    $ cat sample.txt
    Title

    message : hogehoge
    test1
    test2
    test3
    $
    ```

    キャンセル

  • 2015/07/19 20:26

    回答いただいたスクリプトをコピペで試したのですが自分の環境だと改行がnになってしまうんです。。。
    Titlennmessage : hogehogenfirst line
    MacはOS X10.10.4で
    $ echo $SHELL
    /bin/zsh
    なんですが(´・ω・`)

    キャンセル

  • 2015/07/19 20:29

    ```
    $ cat sample.txt
    test1
    test2
    test3
    $ sed -i"" -e '1s/^/Title\n\nmessage : hogehoge\n/' sample.txt
    $ cat sample.txt
    Titlennmessage : hogehogentest1
    test2
    test3
    ```

    キャンセル

関連した質問

同じタグがついた質問を見る

  • sh

    291questions

    shは、UNIX系OSのシェル操作の1つであり、最も基本的なシェルのことです。