Bash 获取字符串中给定字符/模式每次出现之前的字符

Bash 获取字符串中给定字符/模式每次出现之前的字符,bash,awk,sed,Bash,Awk,Sed,我正在尝试使用标准bash工具grep、awk/gawk、sed等获取字符串中给定字符/模式每次出现之前的字符 步骤I:获取字符每次出现之前的字符: 例如: 字符串1=>:hd:fg:kl: 字符串2=>:df:lkjh: 字符串3=>:glki:l:s:d: 预期结果 结果1=>dgl 结果2=>fh 结果3=>ilsd 我用awk试了很多次,但都没有成功 步骤二:在结果字符串的每个字符之间插入给定字符 带有/ 结果1=>d/g/l 结果2=>f/h 结果3=>i/l/s/d 我有一个用于此步

我正在尝试使用标准bash工具grep、awk/gawk、sed等获取字符串中给定字符/模式每次出现之前的字符

步骤I
:获取字符每次出现之前的字符

例如:

字符串1=>:hd:fg:kl:

字符串2=>:df:lkjh:

字符串3=>:glki:l:s:d:

预期结果

结果1=>dgl

结果2=>fh

结果3=>ilsd

我用awk试了很多次,但都没有成功

步骤二
:在结果字符串的每个字符之间插入给定字符

带有
/

结果1=>d/g/l

结果2=>f/h

结果3=>i/l/s/d

我有一个用于此步骤的awk表达式
awk-F'-v OFS=“/”{$1=$1;print}'

我不知道是否可以使用awk或sed执行
步骤I
,为什么不一次性执行
步骤I
步骤II

问候您这可能对您有用(GNU sed):

在整行中,将零个或多个非
字符后跟一个
字符,或将单个
字符替换为单个字符。然后在每个字符之间插入一个
/

如何:

awk 'BEGIN{FS=":"}{for(i=1;i<NF;i++){if(i>2)printf"/";printf substr($i,length($i))}print""}' input.txt
$ awk <file.txt '{for(i=2;i<=length($0);i++) { \
                    if (substr($0,i,1)==":") printf substr($0,i-1,1);} printf "\n";}'
dgl
fh
ilsd
输出:

d/g/l
f/h
i/l/s/d
解决方案一:请尝试以下内容,并让我知道这是否对您有帮助

awk -F":" '
{
  for(i=1;i<=NF;i++){
    if($i){ val=(val?val:"")substr($i,length($i)) }
  }
  print val;
  val=""
}' Input_file
解决方案2:,在输出字符串之间有一个
/

awk '
BEGIN{
  OFS="/";
  FS=":"
}
{
  for(i=1;i<=NF;i++){
    if($i){
      val=(val?val OFS:"")substr($i,length($i))
    }}
  print val;
  val=""
}' Input_file
解决方案3:使用
匹配
awk的实用程序

awk '
{
  while(match($0,/[a-zA-Z]:/)){
    val=(val?val:"")substr($0,RSTART,RLENGTH-1)
    $0=substr($0,RSTART+RLENGTH)
   }
  print val
  val=""
}'  Input_file

Perl和负前瞻:

$ perl -p -e 's/.(?!:)//g' file
dgl
fh
ilsd

使用
perl

$ cat ip.txt
:hd:fg:kl:
:df:lkjh:
:glki:l:s:d:

$ perl -lne 'print join "/", /.(?=:)/g' ip.txt
d/g/l
f/h
i/l/s/d
  • /。(?=:)/g
    获取前面的所有字符
    • (?=:)
      是一个
  • 然后使用
    /
    作为分隔符字符串打印结果匹配项
与ERE一起使用所有sed

sed -E 's#[^:]*(.):#\1/#g;s/^.|.$//g' infile
使用GNU sed:

sed -E 's/[^:]*([^:]):/\1/g; s/([^:])/\/\1/g; s/^:\///'
第一个命令,
s/[^::]*([^:]):/\1/g
匹配删除多余的字符和冒号(第一个除外),因此产生以下结果:

:dgl
:fh
:ilsd
第二个命令
s/([^:])/\/\1/g
在每个字符前插入一个
/
,产生:

:/d/g/l
:/f/h
:/i/l/s/d
最后一个命令
s/^:\//
只是从每行开头删除
:/

d/g/l
f/h
i/l/s/d

您可以使用gawk从第二个字符开始遍历每一行。每次迭代器碰到冒号时,打印上一个字符

$ awk <file.txt '{for(i=2;i<=length($0);i++) { \
                    if (substr($0,i,1)==":") printf substr($0,i-1,1);} printf "\n";}'
dgl
fh
ilsd

$awk您可能会觉得这个问题很有帮助@moocan,请尝试选择任何一个答案作为正确答案并完全关闭该问题查看此链接以了解更多详细信息您应该在示例输入/输出中包含一个背对背冒号的案例(例如foo::bar)如果发生这种情况,根据您的要求,可能很难处理。输出是
o
还是
o:
还是其他什么?如果这不能发生,那么在你的问题中添加一个陈述,这样说。@RavinderSingh13我为我迟来的回答道歉,因为我offline@Ed莫顿,这在我的情况下是不可能发生的。。。但对于诸如:hfd:l:jh:m之类的模式,这是一个非常好的建议,输出为“d/l/h/m”。在我的问题中,我总是以“:”结束我的例子,这是我的错误,因为它也可以以任何字母结尾。在我的问题中,我总是以“:”结束我的例子,这是我的错误,因为它也可以以任何字母结尾。在模式如:hfd:l:jh:m的情况下,第一个解决方案的输出为“dlhm”,第二个解决方案的输出为“d/l/h/m”。您的第三个解决方案效果很好,因为输出为“dlh”。@moocan,sue感谢您让我知道,请尽量按照您的要求保留问题的样本,因为解决方案将根据您的样本、欢呼声和愉快的学习给出。即使该模式没有以“:”结尾,也适用于我的所有测试模式。”但任何一封信。谢谢
:/d/g/l
:/f/h
:/i/l/s/d
d/g/l
f/h
i/l/s/d
$ awk <file.txt '{for(i=2;i<=length($0);i++) { \
                    if (substr($0,i,1)==":") printf substr($0,i-1,1);} printf "\n";}'
dgl
fh
ilsd