2017-01-17 9 views
-1

別の質問では、ユーザー@Cyrusはhow to extract the dates from a filenameを説明しました。私はファイル名に他の数字のゴミが存在する可能性のあるファイルについて説明しなければなりません。Bashのファイル名から数字の塊だけを抽出する方法は?

一部のファイルにはプレフィックスが付いています。たとえば:のみの塊を抽出する方法はあり

for i in *; do 
    [[ $i =~ [0-9]{8}|[0-9]{4}-[0-9]{2}-[0-9]{2} ]] 
    x="${BASH_REMATCH[0]//-/}" 
    y="${x:0:4}" 
    m="${x:4:2}" 
    d="${x:6:2}" 
    echo "$y $m $d" 
done | sort -n 

:(下)

01 - Camera 03 - 20161231.mp4 
02 - Camera 03 - 20161231.mp4 
03 - Camera 03 - 20161231.mp4 

彼のオリジナルの答えは、このゴミを持っていないファイル名を想定し、それを行う方法を示しています特定のパターンに適合するファイル名ですか?たとえば:

出力:

他の質問と同様に

yyyyMMdd 
yyyyMMddHHmmss 
yyyy-MM-dd HH-mm-ss 

、私の目標は、ごみ(接頭辞、非日付数値など)を無視してDATE部分から値を取得することです

 
2010 12 20 
2016 01 01 
2016 04 13 
2017 01 11 
2017 01 17 16 02 30 

ありがとうございます。

+0

あなたの質問にそのサンプル入力のサンプル出力を追加してください。 – Cyrus

+0

最初に文字列をパターンに適合させて*分割*することはできませんでしたか?たとえば、 'parts = $(echo $ file | tr" "" \ n ")'のようにします。 –

+0

bashパラメータの拡張にはいくつかのパターンマッチング修飾子があります。あなたはそれらを記述するマニュアルのセクションを見ましたか? https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html#Shell-Parameter-Expansion – Barmar

答えて

1

スクリプトにこれを置く:

#!/bin/bash -ue 

match_timestamp() 
{ 
local 
local -r line="$1" 

[[ "$line" =~ $TIMESTAMP_PATTERN ]] || return # Return if non-matching 

# We have a match 
echo "Match found" 
echo " Line received : $line" 
echo "  Timestamp : " 

YR="${BASH_REMATCH[2]}" 
MO="${BASH_REMATCH[4]}" 
DM="${BASH_REMATCH[6]}" 
HH="${BASH_REMATCH[8]}" 
MM="${BASH_REMATCH[10]}" 
SS="${BASH_REMATCH[12]}" 

if 
    [[ "$YR" ]] && [[ "$MO" ]] && [[ "$DM" ]] 
then 
    # The date is available, we print it 
    echo -n " $YR-$MO-$DM" 
    if 
    [[ "$HH" ]] && [[ "$MM" ]] 
    then 
    # The time is available, we print it 
    echo -n " $HH:$MM" 
    if 
     [[ "$SS" ]] 
    then 
     # Seconds are available, we print that too 
     echo -n ":$SS" 
    fi 
    fi 
    echo 
fi 

} 

main() 
{ 

# Constants declared here once, reused in other function (regex patterns) 
local -r PYR="([12][0-9][0-9][0-9])" 
local -r PMO="([01][0-9])" 
local -r PDM="([1-9]|[0-3][0-9])" 
local -r PHH="([0-2][0-9])?" 
local -r PMM="([0-5][0-9])?" 
local -r PSS="([0-5][0-9])?" 

# Pattern for separator between fields (including no separator at all) 
local -r SP="([^0-9a-zA-Z]*)" 
# Pattern for anything but a digit 
local -r NAD="[^0-9]" 
# Big pattern that matches timestamps with flexibility 
local -r TIMESTAMP_PATTERN="(^|$NAD)$PYR$SP$PMO$SP$PDM$SP$PHH$SP$PMM$SP$PSS($NAD|$)" 

local line 

if 
    [[ -t 0 ]] 
then 
    for line in "[email protected]" 
    do 
    match_timestamp "$line" 
    done 
else 
    while IFS= read -r line 
    do 
    match_timestamp "$line" 
    done 
fi 
} 

main "[email protected]" 

このスクリプトは、標準入力(1行に1つずつ)に文字列(ファイル名または他の方法)を受け取ることができるか、引数として文字列を設けて、標準入力が端末に接続されていない場合は、最初のモードが適用され、それ以外の場合は2番目のモードが適用されます。

提案されているように、それは4桁の年、2桁の月、日、時、分、秒にのみ一致します。しかし、月の日以降のものは省略することができ、見つかった部分(小さな連鎖正規表現で作られた単一の大きな正規表現)と引き続き一致します。 regexesを微調整することで柔軟性を追加することができます。セパレータを使うこともできない(セパレータの正規表現のおかげで)。

パターンは耐弾性ではありません(例:25時間、2月30日は受け付けます)が、基本的な目的では有効です。

それがどれだけ素晴らしいかを見て、それは私が保つつもりです!

関連する問題