简体   繁体   English

仅当变量具有值时sed bash替换

[英]sed bash substitution only if variable has a value

I'm trying to find a way using variables and sed to do a specific text substitution using a changing input file, but only if there is a value given to replace the existing string with. 我试图找到一种使用变量的方法,并使用sed使用变化的输入文件来进行特定的文本替换,但前提是必须提供一个值来替换现有字符串。 No value= do nothing (rather than remove the existing string). 无值=不执行任何操作(而不是删除现有字符串)。

Example Substitute.csv contains 5 lines= 示例Substitute.csv包含5行=

this-has-text
this-has-text

this-has-text
this-has-text

and file.text has one sentence= 并且file.text有一个句子=

"When trying this I want to be sure that text-this-has is left alone."

If I run the following command in a shell script 如果我在shell脚本中运行以下命令

Text='text-this-has'
Change=`sed -n '3p' substitute.csv`
grep -rl $Text /home/username/file.txt | xargs sed -i "s|$Text|$Change|"

I end up with 我最终

"When trying this I want to be sure that is left alone."

But I'd like it to remain as 但我希望它保持原样

"When trying this I want to be sure that text-this-has is left alone."

Any way to tell sed "If I give you nothing new, do nothing"? 有什么办法告诉sed:“如果我不给您新的东西,什么也不做”?


I apologize for the overthinking, bad habit. 我为过度思考,坏习惯而道歉。 Essentially what I'd like to accomplish is if line 3 of the csv file has a value - replace $Text with $Change inline. 本质上,我想完成的是csv文件的第3行是否具有值-用$ Change inline替换$ Text。 If the line is empty, leave $Text as $Text. 如果该行为空,则将$ Text保留为$ Text。

Text='text-this-has'
Change=$(sed -n '3p' substitute.csv)
if [[ -n $Change ]]; then
    grep -rl $Text /home/username/file.txt | xargs sed -i "s|$Text|$Change|"
fi

Just keep it simple and use awk: 保持简单并使用awk:

awk -v t="$Text" -v c="$Change" 'c!=""{sub(t,c)} {print}' file

If you need inplace editing just use GNU awk with -i inplace . 如果需要就地编辑,只需将GNU awk与-i inplace

Given your clarified requirement, this is probably what you actually want: 考虑到您的明确要求,这可能是您真正想要的:

awk -v t="$Text" 'NR==FNR{if (NR==3) c=$0; next} c!=""{sub(t,c)} {print}' Substitute.csv file.txt

Testing whether $Change has a value before launching into the grep and sed is undoubtedly the most efficient bash solution, although I'm a bit skeptical about the duplication of grep and sed ; 毫无疑问,在启动grepsed之前测试$Change是否具有值是最有效的bash解决方案,尽管我对grepsed的复制有些怀疑; it saves a temporary file in the case of files which don't contain the target string, but at the cost of an extra scan up to the match in the case of files which do contain it. 对于不包含目标字符串的文件,它将保存一个临时文件,但是对于包含目标字符串的文件,则需要额外扫描直到匹配。

If you're looking for typing efficiency, though, the following might be interesting: 但是,如果您正在寻找打字效率,那么以下内容可能会很有趣:

find . -name '*.txt' -exec sed -i "s|$Text|${Change:-&}|" {} \;

Which will recursively find all files whose names end with the extension .txt and execute the sed command on each one. 它将以递归方式查找所有名称以.txt扩展名结尾的文件,并在每个文件上执行sed命令。 ${Change:-&} means "the value of $Change if it exists and is non-empty, and otherwise an & "; ${Change:-&}表示“ $Change的值(如果存在且为非空值,否则为 ”; & in the replacement of a sed s command means "the matched text", so s|foo|&| &在替换sed s命令时表示“匹配的文本”,因此s|foo|&| replaces every occurrence of foo with itself. 用自身替换每次出现的foo That's an expensive no-op but if your time matters more than your cpu time, it might have been worth it. 那是一个昂贵的无操作,但是如果您的时间比您的cpu时间重要,那可能是值得的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM