![如何提取文件名中具有特定模式的部分?](https://linux22.com/image/160117/%E5%A6%82%E4%BD%95%E6%8F%90%E5%8F%96%E6%96%87%E4%BB%B6%E5%90%8D%E4%B8%AD%E5%85%B7%E6%9C%89%E7%89%B9%E5%AE%9A%E6%A8%A1%E5%BC%8F%E7%9A%84%E9%83%A8%E5%88%86%EF%BC%9F.png)
我正在寻找提取我当前正在使用的位置的文件名的一部分,但它没有按预期输出工作。
样本数据:
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
我希望从文件名中提取文件部分,从病房日期左侧的所有内容(包括下划线(_))并将其分配给 vairable
期望的输出:
变量文件是它需要保存值的东西,这样我就可以传入 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 作为输出/输入分隔符的afind
和 a ):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 作为记录(即文件名)分隔符,以避免任何文件名中存在空格、换行符、shell 元字符等的任何潜在问题。./
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_