bash 文字列スライスで式の出力を使用する

bash 文字列スライスで式の出力を使用する

長さが不明なパスからファイル名の部分文字列を抽出したいです。この 2 つの部分を別々に実行することはできますが、一時変数を使用せずに 2 つを組み合わせる方法はあるのでしょうか?

INPUT_PATH=/path/to/subfolder/file_17.txt 
# I would like to extract "17", the filname will always be 'file_XX.txt'
# The subfolder name is variable length 

TMP=$(basename ${INPUT_PATH})
FILE_NUMBER=${TMP:5:2}
echo ${FILE_NUMBER} # This works as expected

試してみました${$(basename $INPUT_PATH):5:2}が、間違った置換エラーが発生します。これを行うには何かコツがありますか?

答え1

問題に対して異なるアプローチを取り、bash機能のみを使用した 1 行のソリューションを提供します。

$ cat demo.sh
#!/bin/bash

INPUT_PATH=/path/to/subfolder/file_17.txt

FILE_NUMBER=${INPUT_PATH:((${#INPUT_PATH} -6)):2}
echo ${FILE_NUMBER}
$

$./demo.sh
17

もっと簡単な方法は、文字列の末尾から逆算することです。

FILE_NUMBER=${INPUT_PATH: -6:2}

明らかに、このソリューションは、「##XXXX」で終わる文字列変数に依存します。ここで、「##」は対象の 2 桁で、「XXXX」は文字列の最後の 4 文字です。

答え2

bash を使用しているので、正規表現マッチングを使用できます。

if [[ $input =~ ([[:digit:]]+)\.txt$ ]]; then
    file_num=${BASH_REMATCH[1]}
fi

答え3

最も簡単な方法は、TMP の代わりに FILE_NUMBER を使用することです。

FILE_NUMBER=$(basename ${INPUT_PATH})
FILE_NUMBER=${FILE_NUMBER:5:2}

また、パラメータ展開を使用すると、basename を呼び出すよりも高速になります。

FILE_NUMBER=${INPUT_PATH##*/}
FILE_NUMBER=${FILE_NUMBER:5:2}

sed を使用するとすべてを 1 行で実行できますが、速度が遅くなり、読みにくくなります。

FILE_NUMBER=$(sed 's|.*/||;s/.....\(..\).*/\1/' <<<"$INPUT_PATH")

答え4

zshの代わりにを使用する場合bash:

  • 6番目から7番目の文字しっぽbasenameパスの( によって返される部分):

    num=${${a_path:t}[6,7]}
    

    (病気になる$var:tから)csht

    互換性のために最近追加された演算子num=${"$(basename -- "$a_path")":5:2}を使用することもできます。コマンド置換は引用符で囲む必要があります。そうすることで配列が生成されず、配列項目の範囲ではなく文字の範囲が選択されます。ただし、コマンド置換を使用して実行すると、の組み込み演算子を使用するよりも効率と信頼性が低下します。ksh93 ${var:offset:length}zsh:5:2basenamezsh:t

  • 最初の数字の並びしっぽ:

    num=${(MS)${a_path:t}##<->}
    

    ${var##pattern}patternは、 from に一致する最長の先頭文字列を削除する ksh 演算子です$varMフラグを使用すると、M削除される代わりに、 attached 部分が返され、先頭だけでなく ubstringsSも検索されます。また、任意の数字シーケンス (境界は指定されていません) と一致します。S<-><x-y>

  • _aの後の数字のシーケンスしっぽ:

    num=${${a_path:t}/(#m)*_(<->)*/$match[1]}
    

    ( が必要です。 がないextendedglob場合は完全な末尾を返すことに注意してください)。_digits$a_path

    または:

    [[ $a_path:t =~ '_([[:digit:]]+)' ]] && num=$match[1]
    

関連情報