特定のパターンでファイル名の一部を抽出する方法は?

特定のパターンでファイル名の一部を抽出する方法は?

現在作業中の場所のファイル名の一部を抽出しようとしていますが、予想される出力とは機能しません。

サンプル:

ls -a *0728*dat | ls -a *0728*dat |種類

amnbmnbm_jnjmnm_sd_07282019_14_13_17.dat
amnbmnb_kjhkj_07282019_11_23_22.dat
njnkjnjk_AbnBCBB_DE_07282019_07_09_04.dat

ファイル名からファイル部分、病棟日の左側のすべての項目(アンダースコア(_)を含む)を抽出して変数に割り当てたいと思います。

希望の出力:

変数ファイルは、forループに渡すために値を保持するために必要なファイルです。

文書:

amnbmnbm_jnjmnm_sd_
amnbmnb_kjhkj_
njnkjnjk_AbnBCBB_DE_


for file_name in "${file[@]}"
do

echo " file_name=$file_name"

done

希望の出力:

amnbmnbm_jnjmnm_sd_
amnbmnb_kjhkj_
njnkjnjk_AbnBCBB_DE_

答え1

おそらく:

for file_name in *0728*dat
do
  printf '%s\n' "${file_name%[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]_[0-9][0-9]_[0-9][0-9]_[0-9][0-9].dat}"
done

これにより、各ファイル名の末尾に8桁、アンダースコア、2桁、アンダースコア、2桁、アンダースコア、2桁、。などのパターンが削除されます.dat

答え2

sedを使用してください:

ls -a *0728*dat | sed 's/[0-9].*//'
amnbmnb_kjhkj_
amnbmnbm_jnjmnm_sd_
njnkjnjk_AbnBCBB_DE_

または

ls -a *0728*dat | sed "s/[0-9]\{8\}_[0-9]\{2\}_[0-9]\{2\}_[0-9]\{2\}\.dat$//"

答え3

以下にはbash、4.4以上、GNUfindとGNU sed(または出力/入力区切り文字でNULをサポートする少なくともaとa find)が必要です。sed

$ mapfile -d '' files < <(find . -maxdepth 1 -type f -iname '*0728*.dat' -print0 | 
    sed -z 's:^\./::; s/[0-9][0-9_]\+.dat//')

先行、日付と時刻、および.dat拡張子を削除filesしたら、現在のディレクトリから一致するファイル名でbash配列()を入力します。 NULをレコード(つまりファイル名)区切り文字として使用して、すべてのファイル名でスペース、改行、シェルメタ文字などに関連する潜在的な問題を回避します。./sed

find出力をls他のプログラムの入力として使用したり、他のプログラムのコマンドラインで引数として使用したりしないでください。これは安全ではなく信頼できません。バラよりなぜいいえ解析ls(および実行方法)?

もちろんfind、コマンドを変更して他のパターンと一致するファイルを見つけたり、サブディレクトリなどを見つけることもできます。

例:

$ touch amnbmnbm_jnjmnm_sd_07282019_14_13_17.dat amnbmnb_kjhkj_07282019_11_23_22.dat \
    njnkjnjk_AbnBCBB_DE_07282019_07_09_04.dat

$ mapfile -d '' files < <(find . -maxdepth 1 -type f -iname '*0728*.dat' -print0 | 
    sed -z 's:^\./::; s/[0-9][0-9_]\+.dat//')

$ typeset -p files
declare -a files=([0]="amnbmnbm_jnjmnm_sd_" [1]="amnbmnb_kjhkj_" [2]="njnkjnjk_AbnBCBB_DE_")

$ printf '%s\n' "${files[@]}"
amnbmnbm_jnjmnm_sd_
amnbmnb_kjhkj_
njnkjnjk_AbnBCBB_DE_

関連情報