複数行文字列の最後の行を抽出する

複数行文字列の最後の行を抽出する

出力はexif次のとおりです。

ExifMnoteCanon: Loading entry 0xcf27 ('(null)')...
ExifMnoteCanon: Loading entry 0x3ca8 ('(null)')...
ExifMnoteCanon: Loading entry 0xf88a ('(null)')...
2013:08:22 18:01:16

私のbashスクリプトはこれを変数に保存します。

datetime="$(exif --debug --machine-readable --tag=DateTimeOriginal "$file" 2>&1)"

bashパラメータ置換を使用して最後の行を抽出したいと思います。私はこれがうまくいくと思います:

datetime="${datetime##*\n}"

ただし、出力は次のようになります。

ull)')...
2013:08:22 18:01:16

これがうまくいかない理由と回避策は何ですか?

答え1

ANSI C スタイルのエスケープシーケンスを使用して$'\n'改行を表します。

% echo "$datetime"       
ExifMnoteCanon: Loading entry 0xcf27 ('(null)')...
ExifMnoteCanon: Loading entry 0x3ca8 ('(null)')...
ExifMnoteCanon: Loading entry 0xf88a ('(null)')...
2013:08:22 18:01:16

% echo "${datetime##*\n}"
ull)')...
2013:08:22 18:01:16

% echo "${datetime##*$'\n'}"
2013:08:22 18:01:16

ご覧のとおり、そうでなければ\n文字通り受け入れられますn

答え2

$''今は携帯性がとても良くなりましたが、sh(たとえば、BSDはifをサポートしますが、ダウンストリーム分岐はサポートしませdashん。)、POSIXLY:

eval 'printf "%s\n" "${datetime##*"'"$(printf '\n"')}\""

...迷惑であっても動作します。しかし、私は通常変数に改行文字を保持します$nl

printf "%s\n" "${datetime##*$nl}"

...管理が簡単になりました。もちろん、次のようにすることができます。

printf "%s\n" "${datetime##*"
"}"

...しかし、多分少し面白いと思うかもしれません。

答え3

あるいは、最新バージョンでは、置換を使用して出力を配列に保存し、最後の要素にアクセスすることもbashできます。mapfileexif

mapfile -t arr < <(
         exif --debug --machine-readable --tag=DateTimeOriginal "$file" 2>&1)
printf '%s\n' "${arr[@]:(-1)}"
2013:08:22 18:01:16

関連情報