如何在最后一个下划线字符处剪切字符串?

如何在最后一个下划线字符处剪切字符串?

我有如下文件列表:

[root@ods1 backup]# ls -l
total 93892810
-rw-r----- 1 root root 651248 Feb 17 08:34  abc_def_g_17-02-2022.sql
-rw------- 1 root root 665248 Mar 23 08:46  bbc_23-03-2022.sql
-rw-r----- 1 root root 676992 Apr 04 16:52  zz_b_04-04-2022.sql

我需要实现的是:

abc_def_g
bbc
zz_b

我尝试这样做,但没有成功:

ls -l | awk '{print $9}' | cut -d '_' -f1-2

我怎样才能实现这个目标?获取直到最后一行的任何一系列命令_性格应该胜任这项工作。

编辑:此命令在 CentOS 8 中执行。

答案1

不解析ls,您可以使用简单的loopandshell语法:

for f in *; do echo "${f%_*}"; done

如果您需要进一步处理该列表(并且您有一个能够使用数组的 shell),您可以将项目添加到数组中:

tokens=()
for f in *; do tokens=("${tokens[@]}" "${f%_*}"); done
echo "${tokens[@]}"

或者不使用循环,直接声明数组:

files=(*)
tokens=("${files[@]%_*}")
#or
for token in "${files[@]%_*}"; do echo "$token"; done

答案2

你可以尝试这样的事情:

ls|awk -F_ '{NF-=1}1' OFS=_

这里的技巧是将字段数量减一(删除最后一个字段)

答案3

zshshell 中:

print -r -C1 -- *_*.sql(Ne['REPLY=${REPLY%_*}'])

*_*.sql这使用了一个 glob 限定符,通过删除最后一个下划线之后的所有内容(包括最后一个下划线)来修改与给定的 glob 模式匹配的名称。实际替换是使用标准参数替换进行的。

如果您想使用生成的字符串执行除打印之外的其他操作,请使用通配模式,而不使用 ,print在有意义的地方(例如,在for循环中或作为其他命令的参数)。不要将print上面的命令放入命令替换中!

答案4

不解析输出ls

$ awk 'BEGIN{for (i=1;i<ARGC;i++) { f=ARGV[i]; sub(/_[^_]*$/,"",f); print f }; delete ARGV}' *
abc_def_g
bbc
zz_b

即使您的文件名包含换行符或任何其他字符,这也可以工作。

相关内容