sedに変数を渡すのに問題があります。

sedに変数を渡すのに問題があります。

sedに変数を渡すときに二重引用符を使用する必要があることを知っています。したがって、sedを使用して行番号付きファイルの行を表示するとき:

sed '894!d' cloud.cpp

私はうまくいきましたが、行番号894をsedに変数として渡したいので、次のことを試しました。

lnum=894
sed "$lnum!d" cloud.cpp

ただし、同じ構文を使用する単一引用符も機能しません。

sed "894!d" cloud.cpp

それでは、この場合、どのように変数をsedに渡すことができますか?

答え1

変数に数字のみが含まれている場合、実行している操作は正しいものです。

sed "$lnum!d" cloud.cpp

sed通常、シェル変数を渡すには、次をお読みください。この回答


今、この場合は正しく行いましたが、まだ機能しません。これはシェルによるものbashです。これらのシェルは、(この機能は元々提供されており、後でコピーされる)とマークされている歴史的な拡張をサポートしています。zshcsh!cshbashzsh

では、対話型セッションで履歴拡張がデフォルトbashzsh有効になっており、二重引用符で囲まれています。

存在するzsh

$ seq 10 | sed "10!d" # <-- press enter
$ seq 10 | sed "10dash"

これはdash私の歴史上で始まる最も最近の命令ですd

存在するbash

$ seq 10 | sed "10!d"
bash: !d": event not found

.bashで始まるbashレコードには何もないからですd

履歴拡張をオフにできます。

set +H

または:

set +o histexpand

一緒にするbash

set -K

または:

setopt nohistexpand

存在するzsh


より移植可能な方法のために、シェルオプションに頼らずにいつでも次のことができます。

sed "$lnum"\!d cloud.cpp

これにより、シェルは文字通り!処理されます。

答え2

前述のように、文字列に一重引用符を使用すると、その内容は文字通り処理されるため、二重引用符を使用する必要があります。しかし、あなたの場合、パターンと変数の組み合わせがあります。したがって、パターンには一重引用符を、変数には二重引用符を使用する必要があります。

sed "$lnum"'!d' cloud.cpp

答え3

どのシェルを使用しているのか言及していません。以下の回答は次のとおりですbash


シェルで履歴拡張をトリガしています。からman bash

!string

文字列で始まる履歴リストの現在位置より前の最新コマンドを参照します。

奇妙なことは次のとおりです。

!有効にすると、二重引用符内に表示される内容がバックスラッシュを使用してエスケープされていない限り、履歴拡張が行われます。前のバックスラッシュは! 削除されません。

だから私はそれらを個別に引用するのがおそらく最良の解決策だと思います。

sed "$lnum"'!d' cloud.cpp

これも動作します(キャラクターを保存します):

sed "$lnum"\!d cloud.cpp

これも機能します(二重引用符を好む場合):

sed "$lnum""!""d" cloud.cpp

関連情報