変数をsedに渡すときは、二重引用符を使用する必要があることを知っています。したがって、sedを使用して、行番号を指定してファイルの行を表示すると、次のようになります。
sed '894!d' cloud.cpp
動作しますが、行番号894を変数としてsedに渡したいので、次のように試みました。
lnum=894
sed "$lnum!d" cloud.cpp
しかし、これは機能せず、同じ構文の単一引用符でも機能しません。
sed "894!d" cloud.cpp
したがって、この場合、どのようにして変数をsedに渡すことができますか?.
既に述べたように、文字列に単一引用符を使用すると、その内容は文字どおりに扱われるため、二重引用符を使用する必要があります。しかし、あなたの場合、パターンと変数の組み合わせがあります。したがって、パターンには一重引用符を使用し、変数には二重引用符を使用する必要があります。
sed "$lnum"'!d' cloud.cpp
変数に数字のみが含まれている場合、行ったことは正しいです。
sed "$lnum!d" cloud.cpp
一般に、シェル変数をsed
に渡すには、 この答え をお読みください。
これで、この場合は正しく実行できましたが、それでも機能しません。それはおそらくbash
、zsh
またはcsh
のシェルによるものです。これらのシェルは、!
で示される履歴拡張をサポートします(この機能はcsh
からオリジナルであり、bash
およびzsh
によって後でコピーされます)。
bash
、zsh
では、履歴の拡張はインタラクティブセッションでデフォルトで有効になっており、二重引用符内で実行されます。
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の履歴にはコマンドがないため、d
で始まります。
履歴の拡張をオフにすることができます:
set +H
または:
set +o histexpand
bash
および
set -K
または:
setopt nohistexpand
zsh
にあります。
より移植性の高い方法では、シェルオプションに依存せずに、いつでも次のことができます。
sed "$lnum"\!d cloud.cpp
これにより、シェルは!
を文字通り処理します。
使用しているシェルについては触れませんでした。以下の答えは、それがbash
であることを前提としています。
シェルで履歴の拡張をトリガーしています。 man bash
から:
!string
文字列で始まる履歴リストの現在位置の前にある最新のコマンドを参照してください。
それについて奇妙なことはそれです:
有効にすると、二重引用符で囲まれた
!
がバックスラッシュを使用してエスケープされない限り、履歴の展開が実行されます。!
の前のバックスラッシュは削除されません。
したがって、私はそれらを別々に引用することがおそらく最良の解決策だと思います:
sed "$lnum"'!d' cloud.cpp
これも機能します(charを保存します)。
sed "$lnum"\!d cloud.cpp
これも機能します(二重引用符を使用する場合)。
sed "$lnum""!""d" cloud.cpp