我想在 Ubuntu 14.04.1 64 位 LTS 上的 Bash 中提取以“hsli”开头并以“.h5”结尾的文件名的数字部分。我的ls -l hsli*
输出如下:
-rwxrwxrwx 1 ongun ongun 31392 Feb 26 13:04 hsli0.03.h5
-rwxrwxrwx 1 ongun ongun 31392 Feb 26 13:44 hsli0.042.h5
-rwxrwxrwx 1 ongun ongun 31392 Feb 26 14:24 hsli0.054.h5
-rwxrwxrwx 1 ongun ongun 31392 Feb 26 15:03 hsli0.066.h5
-rwxrwxrwx 1 ongun ongun 31392 Feb 26 15:42 hsli0.078.h5
-rwxrwxrwx 1 ongun ongun 31392 Feb 26 16:22 hsli0.09.h5
-rwxrwxrwx 1 ongun ongun 31392 Feb 26 17:02 hsli0.102.h5
-rwxrwxrwx 1 ongun ongun 31392 Feb 26 17:36 hsli0.114.h5
-rwxrwxrwx 1 ongun ongun 31392 Feb 26 17:58 hsli0.126.h5
-rwxrwxrwx 1 ongun ongun 31392 Feb 26 18:20 hsli0.138.h5
-rwxrwxrwx 1 ongun ongun 31392 Feb 26 18:42 hsli0.15.h5
它们已经按升序排列,经过一些操作后,我可以使用以下命令获取第一个文件的文件名。命令和输出如下:
$ ls -l hsli* | head -1 | rev | cut -f 1 -d " " | rev
hsli0.03.h5
现在我的目标是从这里提取0.03
,我该怎么做呢?我不熟悉正则表达式,这似乎是一个困难的情况,因为文件名中有 2 个点。
答案1
如果没有ls
,因为无论如何你只是用 shell glob 填充它的列表,所以你可以像这样删除中间人:
glob_hsli()(IFS=.;set +f
set -f -- '' hsli*.*.h5
for h5 do case ${h5#*.} in
(*[!0-9]*.*|.*|'') : ;;
(*) set $h5 "${1:-0}";
shift $((3>>($2>$4)));;
esac;done
printf "0.%d\n" "${1:?No Match Found!}"
)
不带参数调用它,它将全局化您的文件,并且仅打印当前目录结果中hsli*
第一个出现的中间部分,或者如果它不能这样做,它将返回错误并打印到 stderr 的有意义的错误消息。*.string.h5
答案2
Bash 使得应用像这样的转换相对容易剥离前缀和后缀到数组的元素。
shopt -s nullglob # if there are no matches, produce an empty list
versions=(hsli*.h5) # list matches
versions=("${versions[@]#hsli}") # strip prefix
versions=("${versions[@]%.h5}") # strip suffix
printf '%s\n' "${versions[@]}" # print one version per line
for v in "${versions[@]}"; do # execute a command on each version
somecommand "$v"
done
请注意,版本(如果是这样的话)按字典顺序排序,因此 eg0.9
位于0.10
.如果您想要数字顺序并且您有足够新的 GNU coreutils 版本,则可以使用sort -V
to sort 0.9
before 0.10
。鉴于您的文件名不包含空格或通配符,您可以使用以下命令对它们进行排序
versions=($(printf '%s\n' "$versions[@]" | sort -V))