特定の行でのOSX挿入のsed


24

だから私はしばらくの間linuxで 'sed'を使用していましたが、 'POSIX sed'と 'GNU sed'には多くの小さな違いがあるため、OSXで使用するのに少し苦労しました。現在、特定の行番号の後にテキスト行を挿入する方法に苦労しています。(この場合、4行目)

Linuxでは、次のようなことをします。

sed --in-place "4 a\  mode '0755'" file.txt

OSXでこれを試しました:

sed -i "" "4 a\ mode '0755'" file.txt

ただし、これにより、「コマンドの最後にある\の後の余分な文字」エラーが表示され続けます。ここで何が間違っているのでしょうか?タイプミスはありますか?または、sedのバージョン間の別の違いを理解していないのですか?


2
これがMacOS 10.6.8で動作しないことを確認できます。Debian 6.0.3で正常に動作します。
ティンク

回答:


24

厳密に言えば、POSIX仕様でsedは、次の後に改行が必要a\です。

[1addr]a\
text

前述のように、テキストを標準出力に書き込みます。

これは、ワンライナーおそらく以下の理由で、痛みのビット、書き込みになりGNUの拡張ai、およびcコマンドを:

GNU拡張機能として、a改行と改行文字の間に空白\シーケンス以外が存在する場合、この行のテキストは、の後の最初の非空白文字で始まりaテキストブロックの最初の行として扱われます。(これにより、1行の追加のスクリプトを簡単に作成できます。)この拡張機能は、iおよびcコマンドでも機能します。

したがって、sed構文を移植できるようにするには、a\何らかの方法で改行を含める必要があります。最も簡単な方法は、引用符で囲まれた改行を挿入することです。

$ sed -e 'a\
> text'

(ここで$and >はシェルプロンプトです)。苦痛を感じる場合、bash[1]には$' 'Cスタイルのエスケープを挿入するための引用構文があるので、

sed -e 'a\'$'\n''text'

[1]およびmksh(r39b +)および一部の非bash bourneシェル(たとえば、FreeBSD 9+の/ bin / sh)


非常に有益な答え。bashの引用構文に関するヒントをありがとう。
cjackson

14

この回答で説明されているようにi、やなどのsedコマンドaを使用する場合は、複数の-e "..."句を使用すると便利です。これらの各句は、改行で区切られていると理解されます。iそしてaコマンドは、インラインで使用するのは難しいですが、特にスクリプトをsedは(それらは複数行で使用するために設計されているスクリプトファイルを使用して呼び出されるのsed sed -f file ...)。-e句の終わりによって導入される暗黙的な改行を使用して、a\追加するテキストの行と行を区切ることはできないようです。ただし、追加するテキスト行を終了するために使用できます。

この特定の場合、あなたがやろうとしていることは、実際には単一の-e ...句で達成されるかもしれません。aコマンドを正しく使用する必要があります。POSIX標準でaは、後にが必要であり\、その後に改行が必要です。次に、次の行の残りが挿入されます(改行または-e句の終わりに達するまで)。だからあなたができる:

sed -i "" -e $'4 a\\\n'"mode '0755'" file.txt

2
Gnu-ismsに依存してきた機能を整理したい場合、このページが役立つかもしれません:wiki.alpinelinux.org/wiki/Regex。ただし、正規表現機能のみに制限されています。他のsedコマンドではありません。
-dubiousjim

5

GNU sedは、とにかく使用した例/チュートリアルに基づいて、POSIX sedよりもはるかに一般的に使用されているようです。

私が使用しているOSXマシンにGNU sedをインストールする方がはるかに簡単であることがわかりました。興味があるなら、これを行う最良の方法はHomebrewを通してインストールすることです。

単に$ brew install gnu-sed、またはすべての一般的なGNUユーティリティを入手できます$ brew install coreutils

次に、dateまたは他のプログラムで構文の問題が発生した場合、GNUバージョンを使用できます。最終的には、GNUバージョンを常に使用し、システムバージョンよりも前に配置する方が簡単だと判断しましたPATH


5

Perlは、そのようなプラットフォーム依存のGNU対非GNU対「独自の」特異性の影響を受けません。できること:

perl -ni.old -e 'print;if ($.==4) {print "mode 0755\n"}' file

-n' option creates a loop that reads every line of the input file. Unlike its cousin-p (not used here) it doesn't automatically print every line read. The-i invokes in-place replacement. The argument to-i (viz. ".old") can be dropped or changed. It leaves a backup of the unmodified file. The -eスクリプトの始まりを知らせます。

$.ライン-1で始まる、行番号を示しています。したがって、コマンドラインは「ファイル」を読み取り、行番号が4に等しい場合、その行に続いて注入するものを出力します。

Perlのルーツはsed、AWKおよびCであると急いで付け加えます。そのため、単純な置換などの構文はそれほど急な学習曲線ではありません。


いい答えだ!しかし、あなたはそれを少し単純化することができます。これを試してください perl -wlpi.old -e 'print "mode 0755" if $. == 5' file.txt。この-pスイッチはここでうまく機能します(すべての行を印刷するため)。ロジックを「行4の後に印刷」から「行5の前に印刷」に変更するだけです。また、-lスイッチはevery printで"\ n"が自動的に印刷されるようにするので、自分で印刷する必要はありません。
JL
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.