Bashスクリプトには次の変数があります。
file_name='this_is_the_hart_part.csv'
使用
var2=$(echo $file_name | sed -e 's/_{2}\(.*\)_{3}/\1/')
部分文字列 "the"(変数$ file_nameから2と3の間の下線付きの数字)を抽出したいと思います。
しかし、 $var2 は $file_name と同じです。 sedコマンドをどのように変更できますか?
答え1
サポートされている正規表現の種類は、とのsed
非欲張りな一致を許可しません*
。
3番目に区切られたフィールドを取得したいと思います_
。これは最も簡単な方法ですcut
。
cut -d '_' -f 3
または以下を使用してawk
:
awk -F '_' '{ print $3 }'
または、シェルから対応するフィールドの最初の 2 つを連続して削除し、最後を切り取ります。
str=${file_name#*_}
str=${str#*_}
str=${str%%_*}
"$str"
the
最後の言葉ですね。最後のバリアントを使用することは、おそらく3つのバリエーションの中で最も速く安定しているでしょう。
変数置換は、最初の下線を含む先行ビットが削除された${variable#*_}
文字列を生成します。最初の下線から最後まですべての内容が削除さ$variable
れます。これは標準変数の置換です。${variable%%_*}
$variable
ファイル名に変数置換を使用すると、改行文字を含むファイル名を処理できますが、or norawk
は処理できないという利点があります。通常、ファイル名には行中心のテキスト編集ツールを使用しないでください。sed
cut
また、引用符で囲まれていないecho $file_name
ため$file_name
、単語分割(デフォルトでは空白、タブ、および改行でもあるすべての文字$IFS
)を実行し、結果の単語(ファイル名が一致する文字を含む場合)になります。現在のディレクトリのファイル名とシェルが一致することを確認します。ファイル名のバックスラッシュは消えたり、望ましくない影響を与える可能性があります(拡張子を引用しても)。引用符がない場合、シェルはksh
値に対して中括弧拡張も実行します。$file_name
答え2
最初に注意することsed
はテキストデフォルトでは一度に1行だけ処理するユーティリティですが、ファイル名にはすべての文字(改行を含む)または非文字(文字ではない可能性がある)を含めることができます。テキスト)。
返品、引用符のない変数は非常に特別な意味を持ちます。、あなたはこれをほとんど望んでいません。潜在的に非常に危険。
返品、echo
任意のデータを出力するために使用することはできません。printf
代わりに。
また Bourne と同様のシェルの変数割り当て構文はvar=value
、ではありません$var=value
。
echo
printf
以下を使用して、出力全体をsed
パターン空間にロードできます(またはより良い方法)。
printf '%s\n' "$filename" | sed -e :1 -e '$!{N;b1' -e '}'
その後、2番目と3番目の間の部分を抽出するコードを追加できます_
。
var2=$(
printf '%s\n' "$filename" |
sed -ne :1 -e '$!{N;b1' -e '}' -e 's/^\([^_]*_\)\{2\}\([^_]*\)_.*/\2/p'
)
貪欲ではない部分は、境界を越えて一致しないことを保証するのとは対照的に[^_]*
(文字ではないシーケンス)を使用して_
解決されます(文字以外の項目はまだブロックされていますが)。.*
_
この場合、代わりにシェルパラメータ拡張演算子を使用できます。
case $filename in
(*_*_*_*) var2=${filename#*_*_}; var2=${var2%%_*};;
(*) var2=;;
esac
ファイル名がテキストではない場合、または抽出したい部分が改行文字で終わる場合、この方法はよりうまく機能し、より効率的です。
一部のシェルはより高度な演算子を好むzsh
か持っています。ksh93
zsh
:3番目のフィールドを分割し
_
て取得します。var2=${"${(@s:_:)filename}"[3]}
使用
${var/pattern/replacement}
と逆参照(この場合、変数に3つ以上のアンダースコアが含まれていることを最初に確認する必要があります。そうしないと置換はありません。)set -o extendedglob var2=${filename/(#b)*_*_(*)_*/$match[1]}
ksh93
:var2=${filename/*_*_@(*)_*/\1}
答え3
@Kusalananda そうなんですね。sed
無効なツールなので、貪欲ではないマッチングを実行できません。ただし、貪欲ではない一致の[^_]*
回避策を使用できます。
_
したがって、あなたの場合は、次のようにすることができます。
printf '%s\n' "$file_name" | sed -e 's/^[^_]*_[^_]*_\([^_]*\).*$/\1/g'
しかし...あなたのユースケースについては、他のツールを使用する方が良いでしょう...