我有“我爱苏子结婚”,我想把“苏子”改成“莎拉”
firstString="I love Suzi and Marry"
secondString="Sara"
期望的结果:
firstString="I love Sara and Marry"
要用给定的字符串替换 first 出现的模式,请使用
${parameter/pattern/string}
:
#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
echo "${firstString/Suzi/"$secondString"}"
# prints 'I love Sara and Marry'
要替换 all 出现,请使用
${parameter//pattern/string}
:
message='The secret code is 12345'
echo "${message//[0-9]/X}"
# prints 'The secret code is XXXXX'
(这记录在Bash 参考手册,§3.5.3“Shell 参数扩展”。)
注意这个特性不是由 POSIX 指定的——它是一个 Bash 扩展——所以并不是所有的 Unix shell 都实现它。对于相关的 POSIX 文档,请参阅 The Open Group Technical Standard Base Specifications,第 7 期,Shell & Utilities 卷,§2.6.2“参数扩展”。
这完全可以通过 bash 字符串操作来完成:
first="I love Suzy and Mary"
second="Sara"
first=${first/Suzy/$second}
这将只替换第一次出现的;要全部替换它们,请将第一个斜杠加倍:
first="Suzy, Suzy, Suzy"
second="Sara"
first=${first//Suzy/$second}
# first is now "Sara, Sara, Sara"
对于 Dash,所有以前的帖子都不起作用
POSIX
sh
兼容解决方案是:
result=$(echo "$firstString" | sed "s/Suzi/$secondString/")
这将替换每行输入中的第一次出现。添加一个
/g
标志来替换所有出现的地方:
result=$(echo "$firstString" | sed "s/Suzi/$secondString/g")
试试这个:
sed "s/Suzi/$secondString/g" <<<"$firstString"
如果字符串有正则表达式字符,使用 Bash 比
sed
更好。
echo ${first_string/Suzi/$second_string}
它可以移植到 Windows,并且至少可以与 Bash 3.1 一样老。
为了表明你不需要太担心逃跑,让我们把这个:
/home/name/foo/bar
进入这个:
~/foo/bar
但前提是
/home/name
在开头。我们不需要sed
!
鉴于 Bash 为我们提供了魔法变量
$PWD
和 $HOME
,我们可以:
echo "${PWD/#$HOME/\~}"
感谢 Mark Haferkamp 在评论中对引用/转义的说明
~
。*
注意变量
$HOME
是如何包含斜杠的,但这并没有破坏任何东西。
进一步阅读:高级 Bash 脚本指南。
如果必须使用
sed
,请务必转义每个字符。
echo [string] | sed "s|[original]|[target]|g"
如果明天你决定不爱Marry either她也可以被替换:
today=$(</tmp/lovers.txt)
tomorrow="${today//Suzi/Sara}"
echo "${tomorrow//Marry/Jesica}" > /tmp/lovers.txt
必须有50种离开爱人的方式.
因为我不能添加评论。 @ruaka 为了使示例更具可读性,可以这样写
full_string="I love Suzy and Mary"
search_string="Suzy"
replace_string="Sara"
my_string=${full_string/$search_string/$replace_string}
or
my_string=${full_string/Suzy/Sarah}
使用AWK:
firstString="I love Suzi and Marry"
echo "$firstString" | awk '{gsub("Suzi","Sara"); print}'
Pure POSIX shell 方法,不同于 Roman Kazanovskyi 的
sed
-based answer不需要外部工具,只需要 shell 自己的本地参数扩展。请注意,长文件名已被最小化,因此代码更适合放在一行中:
f="I love Suzi and Marry"
s=Sara
t=Suzi
[ "${f%$t*}" != "$f" ] && f="${f%$t*}$s${f#*$t}"
echo "$f"
输出:
I love Sara and Marry
工作原理:
删除最小后缀模式。如果后缀
"${f%$t*}"
“I love
”在$t
“Suzi*
$f
”中,I love
返回“Suzi and Marry
”。 但是如果
t=Zelda
,那么"${f%$t*}"
什么都不删除,并返回整个字符串“I love Suzi and Marry
”。这用于测试
$t
是否在$f
和[ "${f%$t*}" != "$f" ]
中,如果$f
字符串包含“Suzi*
”,则评估为true,否则为false。
如果测试返回 true,使用 Remove Smallest Suffix Pattern
${f%$t*}
"I love
" 和 Remove Smallest Prefix Pattern ${f#*$t}
"and Marry
" 构造所需的字符串,其中第二个字符串$s
“Sara
”在两者之间。用特殊章程替换第一次出现的模式:
${参数/模式/字符串}
用特殊章程替换所有事件的模式:
${参数//模式/字符串}
firstString="I love //Suzi// and Marry"
secondString="Sara"
firstString="${firstString/\/\/Suzi\/\//"$secondString"}"
echo $firstString
它将打印:
I love Sara and Marry
我认为这是您的用例最简洁的形式:
firstString="${firstString//Suzi/$secondString}"
试试这个:
ls *.ext | awk '{print "mv "$1" "$1".newext"}' | sed "s/.ext.newext/.newext/" | parallel {}
基于上面提出的 awk 解决方案,我将扩展它以使用 awk 变量。 这将允许传递包含特殊字符的文本..
aString="I love _p1_ very much!"
aVar="complicated \" text \' with \. special ) chars"
awk -v p1="$aVar" '{gsub("_p1_",p1); print}' <<< $aString
出品:
I love complicated " text ' with . special ) chars very much
用
sed -e
或 bash
替换来实现这个案例是不容易的。
我发现的唯一方法是将字符串存储在文件中,使用 sed 然后将文件内容存储在 var 中:
echo "I love Suzy" > tmp.txt
sed -i "s/Suzy/Sarah/" tmp.txt
set res=`cat tmp.txt`
echo $res
rm tmp.txt
我不知道我使用的是哪种 shell(如果我键入“sh”,我发现的唯一东西是 sh-4.2)但是所有经典语法都失败了,比如简单的
test=${test2}
。
它失败了 2 次:在分配(必须使用 set
)和在 ${}
.
使用
sed
我们可以轻松做到
sed -i "s+$value_to_be_replaced+$with_variable1 "some character" $with_variable2+g" $file_name
这是一个自动 bash 脚本,用于删除早于特定时期的 git 分支。默认设置时间为 3 个月,但您可以在运行 shell 脚本时将以月为单位的时间作为第一个参数传递。
#!/bin/sh
declare -i numberOfMonths=3 # Declare the default period in months
# Check for passed period(In months) parameter
if [ -z "$1" ];
then
# Period not set
echo "Period not set. Assuming delete period to the default $numberOfMonths months period!"
echo ""
sleep 2; # Hold for 2 seconds
else
# Period set
numberOfMonths=$1; # Set the passed period
fi
echo "Deleting branches older than $numberOfMonths months"
echo ""
sleep 1 # Hold for a second
ECHO='echo ' # Custom echo
: '
Initiate loop scanning for branches older than the passed time or set default while excluding the below branches
main, master
'
for target_branch in $(git branch -a | sed 's/^\s*//' | sed 's/^remotes\///' | grep -v 'main$\|master$'); do
# Check period
if ! ( [[ -f "$target_branch" ]] || [[ -d "$target_branch" ]] ) && [[ "$(git log $target_branch --since "$numberOfMonths month ago" | wc -l)" -eq 0 ]]; then
if [[ "$DRY_RUN" = "false" ]]; then
ECHO="" # Print empty
fi
local_target_branch_name=$(echo "$target_branch" | sed 's/remotes\/origin\///') # Get target branch in iteration
local_target_branch_name=${local_target_branch_name/origin\//} # Replace string "origin/" with empty(string)
$ECHO Deleting Local Branch : "${local_target_branch_name}" # Print message
sleep 1 # Hold for a second
git branch -d "${local_target_branch_name}" # Delete local branch
$ECHO Deleting Remote Branch : "${local_target_branch_name}" # Print message
sleep 1 # Hold for a second
git push origin --delete "${local_target_branch_name}" # Delete remote branch
fi
done