22415


eof の前に改行コードがなかった場合に、改行を挿入するスクリプトを記述しようと思いました。(あまりにもそのようなテキストファイルを見かけるため)

[How to add a newline to the end of a
file?](https://unix.stackexchange.com/q/31947)

によって、`sed -e '$a\'`のフィルタをかけることで、ひとまず手元の環境では期待通りに動作したのですが、これぐらいのよくある処理ならば、なるべく
portable になるように、記述したいなと思いました。

質問:

  * posix の範囲内で、 "eof の前に改行コードがなかった場合に改行を挿入するスクリプト"を記述できますか？
  * できる場合、それはどのようなスクリプトになりますか？

調べたこと:

  * [POSIX.1-2008 の sed](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html) は、 `a\`のコマンドをサポートしている様子でした。
  * しかし、同じページの sed の説明の最初にあるように、 sed はそもそも text file しか想定していない様子です。

> The sed utility is a stream editor that shall read one or more text files

  * [POSIX.1-2008, Definitions](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html) の 3.397 Text File や 3.206 Line を見ていると、 text file = line の sequence であり、 line の最後は必ず newline である想定である模様です。


CC BY-SA 3.0
2016-02-22T13:45:40.797
22400
2016-03-09T17:02:01.427
2017-04-13T12:37:20.867
-1
754
question
sh posix
posix で、" eof の前に newline がなかったら newline を挿入" を実装するには？


ファイルの末尾が改行でなければ、ファイル名.new に新たに書出します。  
ただし、サイズ0のファイルに対しては何もしません。

[code]

    f=your_file; c=`tail -c 1 "$f" | tr -d '\\n' | wc -c` && if [ -s "$f" -a $c -eq 1 ]; then echo | cat "$f" - > "$f".new; fi
    
[/code]

`tail` でファイル末尾1バイトを切り出して、`\n` なら `tr` で削除します。  
残った文字の有無を `wc` で取得します。入力文字が `\n` 以外なら `$c` には 1 が入ります。

改行コードの付加は `cat` の本来の使い方で。ファイルと標準入力を結合します。

読みやすく適当に改行を入れます。

[code]

    f=your_file
    c=`tail -c 1 "$f" | tr -d '\\n' | wc -c` && \
    if [ -s "$f" -a $c -eq 1 ]
    then echo | cat "$f" - > "$f".new
    fi
    
[/code]


CC BY-SA 3.0
2016-02-23T03:04:13.017
22415
2016-02-23T03:50:51.330
2016-02-23T03:50:51.330
8431
8431
22400
answer


@emasaka さんと @rou さんのコメント・回答を参考にして、

前提条件: 対象のテキストファイル(もどき)は、 eof の直前に newline を挿入した際には、 Text File として適格なものになる

であるならば、次で処理できそうです。

[code]

    f=my_file
    echo | cat "$f" - | sed -e '${/^$/d}'
    
[/code]

* * *

追記@2016/03/10

ファイルを経由するのではなく、フィルタの方が汎用性たかそうなので、それを関数として実装してみると次になると思います。

[code]

    fix_trailing_newline() {
        { cat; echo; } |
        sed -e '${/^$/d}'
    }
    
[/code]


CC BY-SA 3.0
2016-03-05T10:30:03.033
22834
2016-03-09T17:02:01.427
2016-03-09T17:02:01.427
754
754
22400
answer