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

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

新規登録して質問してみよう
ただいま回答率
85.48%
bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

sed

sedとは、POSIX環境のために作られたコマンドラインエディタです。sedは編集スクリプトの指示のもとに複数のファイルを編集し、標準出力にその結果を出力します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

Q&A

解決済

2回答

7120閲覧

shellスクリプトに記載したsedコマンドでの "}" (中括弧)入力について

tsuchiwalk

総合スコア7

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

sed

sedとは、POSIX環境のために作られたコマンドラインエディタです。sedは編集スクリプトの指示のもとに複数のファイルを編集し、標準出力にその結果を出力します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

1グッド

0クリップ

投稿2017/05/08 07:13

###前提・実現したいこと
linuxのシェルスクリプトでsedコマンドを使用した処理を記載しているのですが思ったような出力にならずに悩んでいます。

###発生している問題・エラーメッセージ
最終的なアウトプットとして、以下のような形式でファイルを作成したいと考えています。
希望する出力例:

subnet: - { "name": "RDS-SBNET02", "address": "172.16.2.192/26", "nsg_name": RDS-NSG }

しかしながら、自分が作成したshellスクリプト(「該当のソースコード」で引用)では現状、以下のような出力になってしまいます。

subnet: } { "name": "RDS-SBNET02", "address": "172.16.2.192/26", "nsg_name": RDS-NSG

###該当のソースコード

bash

1#!/bin/bash 2 3CSVFILE=edit_NW_vars_preparation.txt 4OUTPUTFILE=common_vars_preparation.yml 5 6cp edit_common_vars_preparation.yml ${OUTPUTFILE} 7sed -i -e "/^nsg_name:*/a subnet:" ${OUTPUTFILE} 8 9for line in `cat ${CSVFILE} | grep -v ^#` 10do 11 subnet_name=`echo ${line} | cut -d ',' -f 1` 12 subnet_address=`echo ${line} | cut -d ',' -f 2` 13 subnet_nsg=`echo ${line} | cut -d ',' -f 3` 14 sed -i -e "/subnet:/a \ - \{ \"name\": \"${subnet_name}\", \"address\": \"${subnet_address}\", \"nsg_name\": ${subnet_nsg} \} " ${OUTPUTFILE} 15done

上記sedコマンドの中で、最後に記載する } を \ でエスケープしているのですが、この処理が意図したように働いてくれずに困っています。以下の部分です。
sed -i -e "/subnet:/a \ - { "name": "${subnet_name}", "address": "${subnet_address}", "nsg_name": ${subnet_nsg} }" ${OUTPUTFILE}

sedコマンドについて、どのように記載すれば「希望する出力例:」のような出力にすることができるでしょうか?

###試したこと
①shellスクリプトのsedを以下のように入力した場合

sed -i -e "/subnet:/a \ - \{ \"name\": \"${subnet_name}\", \"address\": \"${subnet_address}\", \"nsg_name\": ${subnet_nsg} " ${OUTPUTFILE}

①出力は以下のようになります

- { "name": "RDS-SBNET02", "address": "172.16.2.192/26", "nsg_name": RDS-NSG

②shellスクリプトのsedを以下のように入力した場合

sed -i -e "/subnet:/a \ - \{ \"name\": \"${subnet_name}\", \"address\": \"${subnet_address}\", \"nsg_name\": ${subnet_nsg} \}" ${OUTPUTFILE}

②出力は以下のようになります

}- { "name": "RDS-SBNET02", "address": "172.16.2.192/26", "nsg_name": RDS-NSG

①の出力結果の最後に、 } を付与して「希望する出力例」のような形にする、というのが実現したいことです。(何故②のような出力になってしまうのかが解っていない状態です)

よろしくお願いします。

ikuwow👍を押しています

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

現象から見てありそうなのは、CSVFILEの改行が\nでなく\r\nになっている。

そのため、$subnet_nsgの末尾に\rがあり、catするとそこで行頭に戻ってしまっている。
ファイルの中身をcat -vすると^Mつまり\rが入っているのが分かると思います。

改行コードを\nにしてください。
tr -d '\r' < edit_NW_vars_preparation.txt > edit_NW_vars_preparation_corrected.txt

なお、{ }は正規表現の特殊文字ですが、挿入テキストの特殊文字じゃ無いので、\の前置は不要です。

投稿2017/05/08 14:05

otn

総合スコア84505

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tsuchiwalk

2017/05/09 08:52

改行コードが原因でした。大変助かりました。 もし、可能であれば、以下教えてください。 >そのため、$subnet_nsgの末尾に\rがあり、catするとそこで行頭に戻ってしまっている というところが理解できておらず、「行頭に戻る」とはどういうことでしょうか?
otn

2017/05/09 09:02

\r (CR) は「カーソル位置を行頭に戻す」という制御コードです。 サンプル: for ((i=1; i<100; i++)) do sleep 1 echo -n $i if (( i % 10 == 0 )) then echo -ne '\r' fi done
tsuchiwalk

2017/05/09 09:12

な、なるほど。。。 >ファイルの中身をcat -vすると^Mつまり\rが入っているのが分かると思います。 まさにその通りでした。 また、サンプルが非常にわかりやすかったです。ありがとうございました。
guest

0

多分、-\-だと思います。

【FYI】
正規表現でエスケープが必要な文字一覧表


テスト結果

テスト環境(2台で実施)
AmazonLinux(en_US.UTF-8)
CentOS6(ja_JP.UTF-8)

bash

1#!/bin/bash 2CSVFILE=/tmp/csv 3OUTPUTFILE=/tmp/test 4for line in `cat ${CSVFILE} | grep -v ^#` 5do 6 subnet_name=`echo ${line} | cut -d ',' -f 1` 7 subnet_address=`echo ${line} | cut -d ',' -f 2` 8 subnet_nsg=`echo ${line} | cut -d ',' -f 3` 9 sed -i -e "/subnet:/a \ \- \{ \"name\": \"${subnet_name}\", \"address\": \"${subnet_address}\", \"nsg_name\": ${subnet_nsg} \} " ${OUTPUTFILE} 10done

/tmp/csv (EOFに改行を2つ入れています)

RDS-SBNET01,172.16.2.192/26,RDS-NSG #RDS-SBNET02,172.16.2.192/26,RDS-NSG RDS-SBNET03,172.16.2.192/26,RDS-NSG RDS-SBNET04,172.16.2.192/26,RDS-NSG RDS-SBNET05,172.16.2.192/26,RDS-NSG

/tmp/test

subnet:

結果

subnet: - { "name": "RDS-SBNET05", "address": "172.16.2.192/26", "nsg_name": RDS-NSG } - { "name": "RDS-SBNET04", "address": "172.16.2.192/26", "nsg_name": RDS-NSG } - { "name": "RDS-SBNET03", "address": "172.16.2.192/26", "nsg_name": RDS-NSG } - { "name": "RDS-SBNET01", "address": "172.16.2.192/26", "nsg_name": RDS-NSG }

投稿2017/05/08 08:00

編集2017/05/08 10:54
lazhuward

総合スコア1294

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tsuchiwalk

2017/05/08 08:25 編集

回答ありがとうございます!- をエスケープしてみたのですが、結果は変わらないようでした。。。 ( - の前には空白を挿入したい為に、\□(円マークスペース)を使用しています ) ■記載内容 sed -i -e "/subnet:/a \ \- \{ \"name\": \"${subnet_name}\", \"address\": \"${subnet_address}\", \"nsg_name\": ${subnet_nsg} \}" ${OUTPUTFILE} ■出力結果 }- { "name": "RDS-SBNET02", "address": "172.16.2.192/26", "nsg_name": RDS-NSG ↑何故か、行の先頭に { が追加されてしまいます。。
lazhuward

2017/05/08 10:39 編集

差し支えなければ、インプットしている ${OUTPUTFILE} の中身を教えてください。 こちらでテストしましたが、正確に動きますね。 キャラセットは何ですか?改行コードはLFにしてますか?
tsuchiwalk

2017/05/09 08:53

ご指摘のとおり、改行コードが原因でした。検証までしていただきありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問