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

問題に異なるアプローチをとり、機能のみを使用して1行のソリューションを提供してくださいbash

$ 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}

また、パラメータ拡張を使用する方がデフォルト名を呼び出すよりも高速です。

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

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

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

答え4

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

  • 文字6〜7basename次によって返されるパス部分:

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

    $var:tでメールをcsh受け取るt

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

  • 最初の数字の順序:

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

    ${var##pattern}patternから一致する最も長い先行文字列を削除するksh演算子$var。このMフラグを使用すると、M追加された部分は削除されるのではなく返され、開始部分だけでなくubstringSも検索されます。範囲が指定されていないすべての数値シーケンスSと一致します。<-><x-y>

  • _次の数字の順序:

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

    (必須extendedglob; _digitsinがない場合は完全なテールを返します$a_path。)

    または:

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

関連情報