我有一个像这样的文件路径名
/dbfs/mnt/dlg2stage/foldername/backupname/201906_load_1_20210623-151602.tar.tgz
我试图只获取六位数字201906
并打印它们。我尝试过sed
但awk
失败了。
答案1
假设这些是您系统上的实际文件,您可以使用 shell 循环轻松提取目录中_
匹配的每个文件的文件名中第一个之前的部分:*_*.tar.tgz
/dbfs/mnt/dlg2stage/foldername/backupname
for pathname in /dbfs/mnt/dlg2stage/foldername/backupname/*_*.tar.tgz; do
name=$( basename "$pathname" )
printf '%s\n' "${name%%_*}"
done
该basename
实用程序将为您提供路径名的文件名部分。鉴于您显示的示例,这会将字符串分配201906_load_1_20210623-151602.tar.tgz
给变量name
。您也可以用来name=${pathname##*/}
做同样的事情(这个参数扩展删除了字符串的初始部分$pathname
,直到并包括最后一个/
)。
参数扩展${name%%_*}
将导致_*
从 value 中删除最长的尾随子字符串匹配$name
。在所示示例中,这将删除第一个_
字符及其右侧的所有内容,留下子字符串201906
,然后使用 打印该子字符串printf
。
答案2
和zsh
:
file=/dbfs/mnt/dlg2stage/foldername/backupname/201906_load_1_20210623-151602.tar.tgz
set -o extendedglob # for (#c6)
first_6_digits_of_file_tail=${(M)${file:t}[0-9](#c6)}
哪里${file:t}
需要尾巴文件的名称(其基本名称),返回匹配模式${(M)var#pattern}
的开头部分。$var
M
POSIXly,您可以使用:
first_6_digits_of_file_tail=$(
LC_ALL=C expr "/$file" : '.*/\([0-9]\{6\}\)[^/]*/*$'
)
LC_ALL=C
忽略用户的区域设置并将所有字节视为字符(大多数系统上按照 ASCII 的第 128 位,包括 / 和 0123456789 数字),以便.
保证[^/]
匹配字节并且[0-9]
仅包括 0123456789。它不是zsh
范围基于的数字codepoints 和 zsh 认为每个字节不以其他方式形成有效字符的一部分,就好像它是一个字符一样。
前置/
以避免以$file
运算符开头-
或看起来像expr
运算符的值出现问题,并保证字符串至少包含/
正则表达式所期望的一个。
我们不允许最后的 except/
之后的 s获得与使用or zsh 的解决方案相同的行为,其中or的基本名称是。/XXXXXX
basename
$file:t
/foo/bar/
/foo/bar////
bar
请注意,如果没有匹配项,而且该 6 位数字序列代表 0 数字(如 中所示/path/to/000000_whatever
),它会返回 false/失败退出状态。
答案3
我想你只是想打印201906
给定的路径字符串。在该示例中,这六位数字是:前面有斜杠的前六位数字。
我将路径放入变量中只是为了使命令更易于阅读:
% path_str='/dbfs/mnt/dlg2stage/foldername/backupname/201906_load_1_20210623-151602.tar.tgz'
% echo $path_str | sed 's/.*\/\([0-9]\{6\}\).*/\1/'
201906
这是我如何建立匹配和替换的sed:
\/[0-9]\{6\}
: 匹配斜杠和 6 位数字\/\([0-9]\{6\}\)
: 是一样的,但现在在捕获组或者子表达式(斜杠不在捕获组中).*\/\([0-9]\{6\}\).*
: 匹配之前和之后的所有内容,所以...整条线\1
:整行匹配,使用参考第一的(且唯一)捕获组仅用前 6 位数字替换整行