形式のファイル名を指定するsomeletters_12345_moreleters.ext
と、5桁を抽出して変数に入れたいと思います。
要点を強調するために、x 個の文字のファイル名と、両側に 1 つのアンダースコアで囲まれた 5 桁のシーケンス、さらに x 個の文字の別のセットがあります。5桁の数字を変数に入れたいです。
これを実現するさまざまな方法に非常に興味があります。
これを行うには、パラメーター拡張を使用できます。
aが定数の場合、次のパラメーター展開によって部分文字列の抽出が実行されます。
b=${a:12:5}
ここで、12はオフセット (ゼロベース) で、5は長さです
数字の周りのアンダースコアが入力内の唯一のものである場合、次の 2 つの手順で接頭辞と接尾辞を (それぞれ) 取り除くことができます。
tmp=${a#*_} # remove prefix ending in "_"
b=${tmp%_*} # remove suffix starting with "_"
他のアンダースコアがある場合は、よりトリッキーではありますが、とにかく実行可能です。単一の式で両方の展開を実行する方法を誰かが知っている場合は、私も知りたいです。
提示された両方のソリューションは純粋な bash であり、プロセスの生成が含まれていないため、非常に高速です。
使用カット:
echo 'someletters_12345_moreleters.ext' | cut -d'_' -f 2
より一般的な:
INPUT='someletters_12345_moreleters.ext'
SUBSTRING=$(echo $INPUT| cut -d'_' -f 2)
echo $SUBSTRING
そのようなシーケンスの最初を使用して、番号がファイル名のどこにでもある一般的なソリューション:
number=$(echo $filename | egrep -o '[[:digit:]]{5}' | head -n1)
変数の一部を正確に抽出する別の解決策:
number=${filename:offset:length}
ファイル名が常にstuff_digits_...
awk を使用できる形式の場合:
number=$(echo $filename | awk -F _ '{ print $2 }')
数字以外のすべてを削除するさらに別のソリューションを使用します
number=$(echo $filename | tr -cd '[[:digit:]]')
使ってみるだけcut -c startIndx-stopIndx
これが私がそれを行う方法です:
FN=someletters_12345_moreleters.ext
[[ ${FN} =~ _([[:digit:]]{5})_ ]] && NUM=${BASH_REMATCH[1]}
説明:
Bash 固有:
[[ ]]
条件式を示します=~
条件が正規表現であることを示します&&
前のコマンドが成功した場合、コマンドをチェーンします正規表現 (RE):_([[:digit:]]{5})_
_
一致する文字列の一致する境界を画定/アンカーするリテラルです()
キャプチャ グループを作成する[[:digit:]]
文字クラスです。それ自体が物語っていると思います{5}
前の文字、クラス (この例のように)、またはグループの正確に 5 つが一致する必要があることを意味します英語では、次のように動作すると考えることができます。FN
文字列は、キャプチャ グループが開か_
れる時点で 5 桁の一致を試みるまで、1 文字ずつ繰り返されます。この時点までの照合が成功した場合、キャプチャ グループは通過した 5 桁を保存します。次の文字が の場合、条件は成功であり、キャプチャ グループが で使用可能になり、次のステートメントを実行できます。照合のいずれかの部分が失敗した場合、保存された詳細は破棄され、文字ごとの処理が. たとえば、whereの場合、一致が見つかるまでに 4 回の不正開始が発生します。_
BASH_REMATCH
NUM=
_
FN
_1 _12 _123 _1234 _12345_
より厳密な情報が必要な場合は、次のように man bash で検索することもできます
$ man bash [press return key]
/substring [press return key]
[press "n" key]
[press "n" key]
[press "n" key]
[press "n" key]
結果:
${パラメータ:オフセット} ${パラメータ:オフセット:長さ} サブストリング展開。の長さの文字まで展開します オフセットで指定された文字から始まるパラメーター。もしも length は省略され、パラメータ start- の部分文字列に展開されます オフセットで指定された文字で ing。長さとオフセットは 算術式 (以下の算術評価を参照)。もしも オフセットがゼロ未満の数値に評価される場合、その値が使用されます パラメータの値の末尾からのオフセットとして。算術 - で始まる式は空白で区切る必要があります from the previous : Use Default と区別する 価値観の拡大。長さが以下の数値に評価される場合 ゼロであり、パラメーターが @ ではなく、インデックス付きでも連想型でもない 配列、値の末尾からのオフセットとして解釈されます 文字数ではなくパラメータの sion は、2 つのオフセットの間の文字です。パラメータが @、結果は off で始まる位置パラメータの長さです。 設定。parameter が @ またはで添字付けされたインデックス付き配列名の場合 *、結果は、で始まる配列の長さのメンバーです ${パラメータ[オフセット]}。に対して負のオフセットが取られます。 指定された配列の最大インデックスより 1 大きい。サブ- 連想配列に文字列展開を適用すると unde‐ 罰金の結果。負のオフセットを分離する必要があることに注意してください 混乱を避けるために、コロンから少なくとも1つのスペースで :- 展開で。部分文字列のインデックス作成はゼロから始まります。 位置パラメータが使用されます。この場合、インデックス デフォルトでは 1 から始まります。オフセットが 0 の場合、位置 パラメータが使用されている場合、$0 がリストの前に付けられます。
jorの答えに基づいて構築します(これは私にはうまくいきません):
substring=$(expr "$filename" : '.*_\([^_]*\)_.*')
「(1つまたは複数の)数字の連続」
という概念に焦点を当てると、
数値を抽出するために、いくつかの外部ツールを使用できます。
sed または tr のいずれかの他のすべての文字を非常に簡単に消去できます。
name='someletters_12345_moreleters.ext'
echo $name | sed 's/[^0-9]*//g' # 12345
echo $name | tr -c -d 0-9 # 12345
しかし、 $name に複数の数字が含まれている場合、上記は失敗します:
「name=someletters_12345_moreleters_323_end.ext」の場合:
echo $name | sed 's/[^0-9]*//g' # 12345323
echo $name | tr -c -d 0-9 # 12345323
正規表現 (regex) を使用する必要があります。
sed と perl で最初の実行 (323 ではなく 12345) のみを選択するには:
echo $name | sed 's/[^0-9]*\([0-9]\{1,\}\).*$/\1/'
perl -e 'my $name='$name';my ($num)=$name=~/(\d+)/;print "$num\n";'
しかし、bash (1)で直接行うこともできます。
regex=[^0-9]*([0-9]{1,}).*$; \
[[ $name =~ $regex ]] && echo ${BASH_REMATCH[1]}
これにより、他のテキスト/文字に囲まれた任意の 長さの数字の最初のランを抽出できます。
注:regex=[^0-9]*([0-9]{5,5}).*$;
正確に 5 桁のランのみが一致します。:-)
(1) : 短いテキストごとに外部ツールを呼び出すよりも高速です。大きなファイルの sed または awk 内ですべての処理を行うよりも高速ではありません。
要件に従う
私は、x文字数のファイル名と、両側に1つのアンダースコアで囲まれた5桁のシーケンス、次にx文字数の別のセットを持っています。5桁の数字を変数に入れたいです。
grep
役に立つかもしれないいくつかの方法を見つけました:
$ echo "someletters_12345_moreleters.ext" | grep -Eo "[[:digit:]]+"
12345
またはそれ以上
$ echo "someletters_12345_moreleters.ext" | grep -Eo "[[:digit:]]{5}"
12345
そして、-Po
構文で:
$ echo "someletters_12345_moreleters.ext" | grep -Po '(?<=_)\d+'
12345
または、正確に 5 文字に合わせたい場合は、次のようにします。
$ echo "someletters_12345_moreleters.ext" | grep -Po '(?<=_)\d{5}'
12345
最後に、変数に格納するには、var=$(command)
構文を使用するだけです。
サブプロセスがなくても、次のことができます。
shopt -s extglob
front=${input%%_+([a-zA-Z]).*}
digits=${front##+([a-zA-Z])_}
これの非常に小さなバリアントもksh93で機能します。
私の答えは、文字列から何を求めているかをより細かく制御できます。12345
文字列から抽出する方法のコードは次のとおりです
str="someletters_12345_moreleters.ext"
str=${str#*_}
str=${str%_more*}
echo $str
や のような文字やabc
特殊文字を含むものを抽出したい場合、これはより効率的です。例: 文字列がこのようなもので、 afterと before のすべてが必要な場合:_
-
someletters_
_moreleters.ext
str="someletters_123-45-24a&13b-1_moreleters.ext"
私のコードを使用すると、正確に何が欲しいかを言及できます。説明:
#*
一致するキーを含む前の文字列を削除します。ここで言及したキーは_
%
、一致するキーを含む次の文字列を削除します。ここで言及したキーは「_more*」です
自分でいくつかの実験を行ってください。これは興味深いものです。
数字の最初のブロックに一致し、周囲のアンダースコアに依存しない接頭辞と接尾辞のソリューション (JB と Darron によって提供されたソリューションに類似) は次のとおりです。
str='someletters_12345_morele34ters.ext'
s1="${str#"${str%%[[:digit:]]*}"}" # strip off non-digit prefix from str
s2="${s1%%[^[:digit:]]*}" # strip off non-digit suffix from s1
echo "$s2" # 12345
sed
正規表現グループを処理する の機能が気に入っています。
> var="someletters_12345_moreletters.ext"
> digits=$( echo "$var" | sed "s/.*_\([0-9]\+\).*/\1/p" -n )
> echo $digits
12345
もう少し一般的なオプションは、数字シーケンスの開始を示すアンダースコアがあると仮定しない_
ことです。したがって、たとえば、シーケンスの前に取得したすべての非数字を取り除きますs/[^0-9]\+\([0-9]\+\).*/\1/p
。
> man sed | grep s/regexp/replacement -A 2
s/regexp/replacement/
Attempt to match regexp against the pattern space. If successful, replace that portion matched with replacement. The replacement may contain the special character & to
refer to that portion of the pattern space which matched, and the special escapes \1 through \9 to refer to the corresponding matching sub-expressions in the regexp.
正規表現に自信がない場合のために、これについて詳しく説明します。
s
_s_substitute用です[0-9]+
1桁以上に一致\1
正規表現出力のグループ n.1 へのリンク (この場合、グループ 0 は一致全体、グループ 1 は括弧内の一致です)p
flag は _p_rinting 用ですすべてのエスケープは、の正規表現処理を機能\
させるためにあります。sed
test.txt が「ABCDEFGHIJKLMNOPQRSTUVWXYZ」を含むファイルであるとします。
cut -b19-20 test.txt > test1.txt # This will extract chars 19 & 20 "ST"
while read -r; do;
> x=$REPLY
> done < test1.txt
echo $x
ST
PHP の substr('abcdefg', 2-1, 3) に似ています。
echo 'abcdefg'|tail -c +2|head -c 3
bash 組み込みの 'expr' コマンドもあります。
INPUT="someletters_12345_moreleters.ext"
SUBSTRING=`expr match "$INPUT" '.*_\([[:digit:]]*\)_.*' `
echo $SUBSTRING
bash ソリューション:
IFS="_" read -r x digs x <<<'someletters_12345_moreleters.ext'
これにより、 という変数が上書きされx
ます。varは varx
に変更できます_
。
input='someletters_12345_moreleters.ext'
IFS="_" read -r _ digs _ <<<"$input"
これは、目的の出力を得るのに役立つかもしれません
コード :
your_number=$(echo "someletters_12345_moreleters.ext" | grep -E -o '[0-9]{5}')
echo $your_number
出力:
12345
少し遅れましたが、この問題に遭遇したところ、次のことがわかりました。
host:/tmp$ asd=someletters_12345_moreleters.ext
host:/tmp$ echo `expr $asd : '.*_\(.*\)_'`
12345
host:/tmp$
日付に %N がない組み込みシステムでミリ秒の解像度を取得するために使用しました。
set `grep "now at" /proc/timer_list`
nano=$3
fraction=`expr $nano : '.*\(...\)......'`
$debug nano is $nano, fraction is $fraction