『忠犬もちしば』のAIを育てるとグッズが貰える!>>

現在、非常に多数のドキュメントの整形を LaTeXを使って自動的に行っています。
問題となっている処理のエッセンスを抜き出すと次のようなもので、テンプレートファイル中の __PATTERN__ という文字列を、その都度指定する文字列($string)に置換した後にplatexでコンパイルする、という流れです。

----------
#!/bin/bash
sed "s/__PATTERN__/$string/" < template.tex > document.tex
platex document.tex
----------

問題は、$string に '_'(アンダーバー)が含まれるケースで、platexのコンパイルでエラーが発生します。
これを回避するには、'_' を '\_' に置換する必要がありますが、上記処理の前に、$string 中の '_' を '\_' に置換する処理を加えても、上記処理の段階で '\' が消えてしまいます。

肝は sed でのエスケープのやり方だと思うのですが、どうにもうまく行きませんので、お知恵を拝借できればと思います。

なお、tex ファイル中、__PATTERN__ は、他のコマンドの引数内で使用されているため、\verb+ + で囲むという手段も使えません。

このQ&Aに関連する最新のQ&A

A 回答 (2件)

""中なら \ は \\ とクォートしないとダメですね.


ちなみに「$string 中の '_' を '\_' に置換する」のはどんな処理ですか?

この回答への補足

ありがとうございます。自己解決しました。

> ""中なら \ は \\ とクォートしないとダメですね.

とのご回答のとおり、最後の置換で \ を一つ残すためには、事前に $string 中の '_' を '\\_' に置換する必要があり、このためには、

sed 's/_/\\\\\\\\_/g'`

と、バックスラッシュを8個並べれば良いようです。

4個でいいと思っていてうまくいかないので質問したのですが、これで解決です。どうして8個必要になるのかがイマイチ理解できていませんが。

補足日時:2008/09/26 00:45
    • good
    • 2

>どうして8個必要になるのか


エスケープを処理するステップが何回もあるからです。

sed "s/__PATTERN__/$string/"

なので、$string に8個の '\' があったとすると、

・sed に渡されるのは4個の '\' になります。(1回目)
・さらに置換ルーチンに渡されるときに2個になります。(2回目)
・置換ルーチンがその2個の'\' を1個の'\'と解釈します。(3回目)

→出力されるのは1つ

というわけです。
    • good
    • 2

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qsedの置換文字に変数を使用したいのですが・・・

あるファイルの特定の文字を変換し、上書きをする処理を行いたいのですが、sedの置換文字に変数が渡せなくて困っています。

例:
X="a"
Y="b"
echo test.txt | sed 's/${X}/${Y/g}' >test.txt

sedでは置換文字に${X}といった変数を使用することはできないのでしょうか?

Aベストアンサー

' ・・・' で囲まれた中の$はそのままドルマークです。変数展開をするなら、'・・・'で囲んではいけません。

何も囲まないか、"・・・"で囲むかです。

Qsedなどで、特定の文字列の後の文字列を抽出したい

sedなどで、特定の文字列の後の文字列を抽出したい

シェルスクリプト内で、sedなどを使って特定の文字列の後の文字列を抽出したいのですが、どうすればいいでしょうか?

たとえば、abcXYZ123defghiのなかから、XYZの後の「123」を抜き出したいです。

echo abcXYZ123defghi | sed ...

のようにして実行させたいです。

Aベストアンサー

日本語対応sedだと日本語数字混じりでもできますね。

echo abcXYZ12357defghi | sed -e 's/^.*XYZ\([0-90-9]*\).*$/\1/' -e 'y/0123456789/0123456789/'
12357

※ 使っている日本語コードの指定は必要かも(例えば、 --ctype=EUC)

echo abcXYZ12357defghi | sed -e 's/^.*XYZ\([0-90-9]*\).*$/\1/'
12357

※ 入力フォームに書いている時はASCIIと日本語の判別がし易いけど回答見るとわかり難いですね。後ろの例での結果57とy/0123456789/の数字部分が日本語です。

Qgrepで検索文字列が完全一致した行だけ取り出す方法

grepの文字列検索で検索文字列が単語として、完全一致した行だけ取り出す方法はないでしょうか?

通常は
grep hoge hoge.txt

と打つと、hogeが含まれる行が出力されますが、今回は含まれる行ではなくて完全に文字列が一致した行だけ取り出したいのです。

例えばhoge.txtの中に
cc ghoge
kkl hogem
jjll hoge
という3行があったとしたら最後の行でhogeという文字が空白で区切られた行だけ取り出したいのです。

何かよい方法があれば教えてください

Aベストアンサー

-w オプションじゃだめですか?

参考URL:http://www.linux.or.jp/JM/html/GNU_grep/man1/grep.1.html

Qbashなどのシェル変数の値に改行を含める事は可能でしょうか?

タイトルの通りですが、通常のシェル変数の値として

 [prompt]$ aaa="bbb<改行>ccc"

のようなセットを行い、

 [prompt]$ echo $aaa
 bbb
 ccc
 [prompt]$

のような結果を得たいのですが、可能でしょうか。

Aベストアンサー

可能です.
というか,やってみたら出来ることがわかると思います.こんなところで聞くより早い.
なお,sh/bash系では改行文字は特にエスケープせずそのまま入れられます.

aaa='bbb
ccc'

QLinux:sedコマンドで置換がしたいです!!

sedコマンドで、「$」、「空白」、「"」を含む文字を置換がしたいのですが、
うまく行きません ><
詳しい方いましたら教えてください m(_ _)m


******************************
置き換え対象の文字列(スペース含む)
******************************
$SUBJECT_TAG_TYPE = "[:]";


***********************
こんな風に置き換えたい
***********************
$SUBJECT_TAG_TYPE = "";


***********************
打ってみたコマンド
***********************
sed -i -e 's/$SUBJECT_TAG_TYPE = "[:]";/$SUBJECT_TAG_TYPE = "";/' ./test.txt

sedコマンドで、「$」、「空白」、「"」を含む文字を置換がしたいのですが、
うまく行きません ><
詳しい方いましたら教えてください m(_ _)m


******************************
置き換え対象の文字列(スペース含む)
******************************
$SUBJECT_TAG_TYPE = "[:]";


***********************
こんな風に置き換えたい
***********************
$SUBJECT_TAG_TYPE = "";


***********************
打ってみたコマンド
***********************
...続きを読む

Aベストアンサー

鍵括弧[] と、ドル記号$ は、
sed の コマンド s/// にて特別な意味を持つ記号です。

なので、エスケープして使いましょう
sed -e 's/\$SUBJECT_TAG_TYPE = "\[:\]";/\$SUBJECT_TAG_TYPE = "";/'

空白と二重引用符には、
特別な意味は無いのでそのままでよいのですが、
エスケープしてもしなくても意味は同じになるので、
怪しいと思った記号は全てエスケープするとよいでしょう。

少々見づらくなる欠点もありますが
sed -e 's/\$SUBJECT_TAG_TYPE\ \=\ \"\[\:\]\"\;/\$SUBJECT_TAG_TYPE\ \=\ \"\"\;/'

Qシェルスクリプトでファイル内の数値文字列を数値として扱うには

失礼します。
シェルスクリプトでファイル内のテキスト(数値文字列)を取得して、それを使って計算するにはどうすれば良いでしょうか?

str:ファイル内のテキスト(数値文字列)

res=$(( $str + 1 ))

・エラー
")syntax error: invalid arithmetic operator (error token is "


よろしくお願いします。

Aベストアンサー

bashをご使用と判断して

res=$(( $str + 1 ))
ではなく、
res=$(( str + 1 ))
だと思います。

> exprもやってみたのですが、処理が遅くなるので使いません。
興味があって以下のシェルで検証してみました。

#!/bin/bash

str=1
i=0

echo 'Using $((str + 1))'
date '+%H:%M:%S.%N'

while [ $i -lt 10000 ]
do
str=$(( str + 1))
i=`expr $i + 1`
done

date '+%H:%M:%S.%N'

exit

$ ./test.sh
Using $((str + 1))
09:18:46.290418000
09:18:56.929345000
これをexprに書き換えたところ
$ ./test2.sh
Using expr
09:19:00.302748000
09:19:19.259990000

exprだと19秒ですが、$(( 演算 )) だと10秒程度なので、演算が多くなれば確かにexprは不利ですね。

bashをご使用と判断して

res=$(( $str + 1 ))
ではなく、
res=$(( str + 1 ))
だと思います。

> exprもやってみたのですが、処理が遅くなるので使いません。
興味があって以下のシェルで検証してみました。

#!/bin/bash

str=1
i=0

echo 'Using $((str + 1))'
date '+%H:%M:%S.%N'

while [ $i -lt 10000 ]
do
str=$(( str + 1))
i=`expr $i + 1`
done

date '+%H:%M:%S.%N'

exit

$ ./test.sh
Using $((str + 1))
09:18:46.290418000
09:18:56.929345000
これをe...続きを読む

Qpingでポートの指定

pingでIPアドレスを指定して、通信できるかどうかというのは
よく使いますが、pingでポートを指定して応答するかどうかは調べられるのでしょうか?

よろしくお願いします

Aベストアンサー

pingを含むICMPというプロトコルは、OSIの7レイヤで言うところのL2(同一セグメント内通信)とL3(IPルーティングされた通信)の両方にまたがる、ちょっと珍しいプロトコルです。

IPアドレスは指定できますが、別サブネットに属するIPアドレスに到達できればL3通信、できなければゲートウェイと呼ばれる同一サブネットに属する中継装置からの回答を得るという点でL2(MAC通信ではなく、同一セグメント内通信という意味)通信です。

ポート番号はL4で使用されるアドレスですから、L4機能の疎通確認はping(を含むICMP)ではできません。

FTPの疎通確認であれば、クライアントからサーバに対するTCP/21通信(FTP-CMD)が可能であること(サーバからクライアントへのTCP/21からの応答を含む)+サーバからクライアントに対するTCP/20通信(FTP-DATA)が可能であること(クライアントからサーバへのTCP/21からの応答を含む)が必要でしょう。

監視ソフトによるものであれば、
・クライアントからサーバへのログイン(TCP/21)
・クライアントからサーバへのlsの結果(TCP/20)
で確認すればよいでしょう。

pingを含むICMPというプロトコルは、OSIの7レイヤで言うところのL2(同一セグメント内通信)とL3(IPルーティングされた通信)の両方にまたがる、ちょっと珍しいプロトコルです。

IPアドレスは指定できますが、別サブネットに属するIPアドレスに到達できればL3通信、できなければゲートウェイと呼ばれる同一サブネットに属する中継装置からの回答を得るという点でL2(MAC通信ではなく、同一セグメント内通信という意味)通信です。

ポート番号はL4で使用されるアドレスですから、L4機能の疎通確認はping(を含む...続きを読む

Qsedで置換した値を変数にセットしたい。

sedで置換した値を変数にセットしたい。
次のように変数aaにセットした文字列「abc」を「abd」に置換して、再度変数aaにセットしたいのですがうまくいきません。
# aa=abc
# aa=`echo $aa | sed -e 's/c/d/'`
sed: -e 表現 #1, 文字数 5: 「s」コマンドが終了していません
#
宜しくお願いします。

Aベストアンサー

それでちゃんと動作してましたが。
sedでエラーになっているので、まずはバッククオートとはずした
echo $aa | sed -e 's/c/d/'
の形で正しく動作するか確認してみては。

ちなみに
echo $aa | sed -e 's/c/d'
としたら、まったく同じエラーになります

QUNIX コマンドにおける # や円マークの意味

お世話になっております。
Unix の表現上の#と¥(円)、セミコロンマークの意味と使い方を教えて下さい。

例 # find . -not -name xxxx -exec cp -v -p --parents {} /mnt/hda1/test/ \;

1.上記の時 # は root によるコマンドプロンプトなので打ち込む必要はないでよいでしょうか

2.上記で¥(円)マークと;(セミコロン)マークの意味は何でしょうか。
  ;(セミコロン)マークは行の終わりとあったのですが、入力する必要がありますか。

3.以下で¥(円)マークは表現上2行になるから記述してあるだけで、
  1行で入力できるなら¥マークを入力しなくてもよいのでしょうか
  それともコマンドラインで2行になるコマンドなので入力してエンターを押し、
  コンソールに2行だと認識させるべきものなのでしょうか
   # nice -5 /usr/bin/pkg - 65536 > \
   /mnt/hda1/hoge

パイプやリダイレクトの意味と使い方は知っているのですが、
複合コマンドは今一つ分かりません。
教えて下さい。よろしくお願いします。

お世話になっております。
Unix の表現上の#と¥(円)、セミコロンマークの意味と使い方を教えて下さい。

例 # find . -not -name xxxx -exec cp -v -p --parents {} /mnt/hda1/test/ \;

1.上記の時 # は root によるコマンドプロンプトなので打ち込む必要はないでよいでしょうか

2.上記で¥(円)マークと;(セミコロン)マークの意味は何でしょうか。
  ;(セミコロン)マークは行の終わりとあったのですが、入力する必要がありますか。

3.以下で¥(円)マークは表現上2行になるから記述してあるだけで...続きを読む

Aベストアンサー

1. このケースでは、おそらくはそうです。
が、本当にシェルスクリプトでのコメントの場合もあります。

2. \には「続く文字との組合せで特別な意味を持たせる」「本来特殊な意味を持つ文字の前に置いて、その意味を無効にする」というのが主な役割りです。
通常、 ;は、複数コマンドを連続実行する際の、各コマンドの区切りとして機能します。
そこで、それを無効にしてセミコロンという文字として使いたい時は
・バックスラッシュ(円マーク)でエスケープする \;
・引用符で文字列にする ';' ";"
等の方法を使います。

ここから先はfindコマンドの話になります。
findコマンドでは -exec 「コマンド」 として見つかったファイルやディレクトリに対して「コマンド」を実行できます。
このときに、どこまでが「コマンド」かを示すために セミコロンを使います。
ところが、 ; そのままではfindコマンド全体の終了と解釈されてしまうので、\; などを使います。

3. このケースでは、1行に書いて問題ありません
\の直後に改行がある場合は、「\改行」をスペースに置き換えたようなものだと考えてください

1. このケースでは、おそらくはそうです。
が、本当にシェルスクリプトでのコメントの場合もあります。

2. \には「続く文字との組合せで特別な意味を持たせる」「本来特殊な意味を持つ文字の前に置いて、その意味を無効にする」というのが主な役割りです。
通常、 ;は、複数コマンドを連続実行する際の、各コマンドの区切りとして機能します。
そこで、それを無効にしてセミコロンという文字として使いたい時は
・バックスラッシュ(円マーク)でエスケープする \;
・引用符で文字列にする ';' ";"
等の方法を使い...続きを読む

Qシェルスクリプトの実行、「source」と「.」の違いについて

bashのシェルスクリプトを書いています。
当方、Mac Snow Leopard を使っているため、seq コマンドがデフォルトでは使えません。
そこで、.bashrc 内に、seq 関数をあらかじめ自分で定義して、他で使い回したいと思っています。
.bashrc の中に、
function seq() {
i=$1
while [ $i -le $2 ] ; do
echo $i
let i=$i+1
done
}
と、関数を定義しました。
seq 関数をターミナル上で実行すると、
>seq 0 2
0
1
2
と正しく、表示されます。次に、

#!/bin/sh
seq 0 2

と記述したシェルスクリプト(temp.sh)を「source」で実行すると、
>source temp.sh
0
1
2
と正しく、表示されますが、「.」で実行すると、
>./temp.sh
./temp.sh: line 2: seq: command not found
と言われます。
どのような理由によってこの違いが出るのでしょうか??

bashのシェルスクリプトを書いています。
当方、Mac Snow Leopard を使っているため、seq コマンドがデフォルトでは使えません。
そこで、.bashrc 内に、seq 関数をあらかじめ自分で定義して、他で使い回したいと思っています。
.bashrc の中に、
function seq() {
i=$1
while [ $i -le $2 ] ; do
echo $i
let i=$i+1
done
}
と、関数を定義しました。
seq 関数をターミナル上で実行すると、
>seq 0 2
0
1
2
と正しく、表示されます。次に、

#!/bin/sh
seq 0 2

...続きを読む

Aベストアンサー

追記

source は現在のシェルで実行し、結果がそのまま現在のシェルに適応されます。
今回の temp.sh なら
> source temp.sh

> seq 0 2
と入力したのと同等ということになります。

> ./temp.sh
この . はコマンドではなく、 temp.shへのパスを指定するものです。
実行ファイル名だけでコマンドとして実行できるのは、環境変数PATHで指定したディレクトリにあるものだけです。それ以外は、その実行ファイルへの絶対パス、または相対パスが必要となります。
これは、カレントディレクトリにある実行ファイルも例外ではありません。
環境変数PATHに . が無い場合は、 ./ファイル名 と相対パスを指定する必要があります。
(この点は、常に . がPATHにあるように振る舞うMS-DOSやコマンドプロンプトとは違います)
逆に、PATH上にあれば(例えば、 PATH=$HOME/bin:(以下略)となっている時の $HOME/bin )、 temp.sh とファイル名だけで実行できます。

また、こうしたコマンドは新規プロセスで実行されますので、環境変数を除いて、現在の設定は継承されません。
対話的ではないbashや、 shとして起動された bash は .bashrcを読まないので、そこに書いてあることは無効となります。

追記

source は現在のシェルで実行し、結果がそのまま現在のシェルに適応されます。
今回の temp.sh なら
> source temp.sh

> seq 0 2
と入力したのと同等ということになります。

> ./temp.sh
この . はコマンドではなく、 temp.shへのパスを指定するものです。
実行ファイル名だけでコマンドとして実行できるのは、環境変数PATHで指定したディレクトリにあるものだけです。それ以外は、その実行ファイルへの絶対パス、または相対パスが必要となります。
これは、カレントディレクトリにある実行...続きを読む


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング