Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 带有“或”条件的sed替换似乎不起作用_Bash_Sed_Sh - Fatal编程技术网

Bash 带有“或”条件的sed替换似乎不起作用

Bash 带有“或”条件的sed替换似乎不起作用,bash,sed,sh,Bash,Sed,Sh,当涉及插入/替换时,我的sed regex或似乎不起作用。给定以下数据文件,如果在第五个字段之后存在关键字,我想在关键字之前插入回车符。然后,想法是打印单独的行。我知道Python、Perl等会更好,但BourneShell是必需的 data.txt: field1 field2 field3 field4 field5 first('echo hello') second('ls /tmp') field1 field2 field3 field4 field5 second('ls -la

当涉及插入/替换时,我的sed regex或似乎不起作用。给定以下数据文件,如果在第五个字段之后存在关键字,我想在关键字之前插入回车符。然后,想法是打印单独的行。我知道Python、Perl等会更好,但BourneShell是必需的

data.txt:

field1 field2 field3 field4 field5 first('echo hello') second('ls /tmp')
field1 field2 field3 field4 field5 second('ls -la /home') forth('ls /tmp')
field1 field2 field3 field4 field5 first ('touch /tmp/hello')
field1 field2 field3 field4 field5 fifth('echo hello world') first('ls /etc') third ('mkdir -p /tmp/blah')
script.sh

#!/bin/sh

while read line; do
    oldifs="$IFS"

    scriptlets=$(echo $line | cut -d ' ' -f 6- | sed -e "s=\(first|second|third|forth|fifth\)=\'$'\n\1=g")
    IFS=$'\n' # this works for Bourne shell 3.2.57
    for scriptlet in $scriptlets; do
        echo "-> $scriptlet"
    done
    IFS="$oldifs"
    echo ""

done < ./data.txt
在-E下的sed中,分组括号不应反斜杠。反斜杠括号与文字括号匹配

此外,您对$scriptlets的赋值缺少用于命令替换的右括号。另外,是否确实要使用命令替换两次,一次在赋值中,一次在for循环中

最后,您可能指的是while read line,而不是for read line,这毫无意义。

这是一条注释,但太长了。有关正确的解决方案,请参阅

这里有很多问题

对于读取行无效;你的意思可能是读台词的时候。 Scriptlet=$。。。缺少一个结束语。 $scriptlets可能不是您想要的-您可能是指${scriptlets} 回音$线有问题。您可能需要引用该变量 Bash与bourneshell不同,尽管它是兼容的。例如,Bourne shell不支持C样式的字符串$'…',如IFS=$'\n中所示。 \n是换行符,\r是回车符。这更像是吹毛求疵,但它可能会让阅读问题的人感到困惑。
尝试使用调试。

显然,您不能将sed或和替换/插入组合在一起。因此,我需要将sed语句分解为单独的语句

scriptlets=$(echo $line | cut -d ' ' -f 6- | sed -e 's/ first/\'$'\nfirst/' -e 's/second/\'$'\nsecond/' -e 's/ third/\'$'\nthird/' -e 's/forth/\'$'\nforth/' -e 's/ fifth/\'$'\nfifth/')

默认情况下,sed使用基本的正则表达式语法,它不支持您所说的交替。要使用交替,请使用sed-E和扩展正则表达式语法。此外,在替换模式中插入换行符的语法也是混乱的。请尝试以下方法:

nl=$'\n'
... | sed -E $'s=(first|second|third|forth|fifth)=\\\n\\1=g' )
但事实上,我也建议用不同的方式编写周围的代码。它当前逐个读取文件中的行,通过cut和sed one传递它们,收集输出,然后使用for将其拆分为更多行。为什么不一次通过cut和sed传递整个文件,然后从中分割输出?另外,通常最好使用while-read循环在行上循环,因为它不会对shell通配符进行愚蠢的操作。这个怎么样:

#!/bin/sh

cut -d ' ' -f 6- data.txt | \
    sed -E $'s=(first|second|third|forth|fifth)=\\\n\\1=g' | \
    while read scriptlet; do
        echo "-> $scriptlet"
    done
echo 
注意,这会导致循环在子shell中运行,因为它在管道中。如果这是一个问题,您需要bash而不是plain sh及其进程替换功能:

#!/bin/bash

while read scriptlet; do
    echo "-> $scriptlet"
done < <(cut -d ' ' -f 6- data.txt | \
         sed -E $'s=(first|second|third|forth|fifth)=\\\n\\1=g' )
echo 

bash不是bourneshell,实际上没有人再使用它了。bash:bourneshell。我想很容易把它们混在一起。
#!/bin/bash

while read scriptlet; do
    echo "-> $scriptlet"
done < <(cut -d ' ' -f 6- data.txt | \
         sed -E $'s=(first|second|third|forth|fifth)=\\\n\\1=g' )
echo