我想要在文件中插入一些Tython函数。插入多行本身可以很好地使用变量和一些\n
,但不保留缩进。因为它是Python代码,这是一个大问题,代码无法正常工作。
以下是我的尝试:
cat sed-insertlines.sh
#!/bin/bash
read -r -d '' lines_to_insert << 'EOF'
def string_cleanup(x, notwanted):\n
for item in notwanted:\n
x = re.sub(item, '', x)\n
return x\n
EOF
lines_to_insert=$(echo ${lines_to_insert} )
sed -i "/import re # Regular Expression library/a $lines_to_insert" sed-insertlines.txt
但这是我cat sed-insertlines.txt
时最终得到的结果:
#!/bin/python
import re # Regular Expression library
def string_cleanup(x, notwanted):
for item in notwanted:
x = re.sub(item, '', x)
return x
def string_replace(i_string, pattern, newpattern):
string_corrected = re.sub(pattern, newpattern, i_string)
return string_corrected
线条在那里,但缩进消失了。
答案 0 :(得分:7)
首先,让我们将数据干净地放入shell变量中。这是一种方式:
lines_to_insert=$(cat<<'EOF'
def string_cleanup(x, notwanted):
for item in notwanted:
x = re.sub(item, '', x)
return x
EOF
)
请注意,没有添加\n
;你可以使用你想要未经修改的文本,但唯一的限制是它不能包含一个由EOF
组成的行(如果有,你可以更改here-doc分隔符。)不幸的是,稍后使用sed
将通过解释一些反斜杠序列来修改文本。
sed a
命令的正确语法如下:
sed -i '/^import re/a \
def string_cleanup(x, notwanted):\
for item in notwanted:\
x = re.sub(item, '', x)\
return x
'
(常见的sed 'a line to insert'
不是Posix标准,并且不允许在行上放置前导空格。正确的语法如上所示; a
后跟空格,后面跟着通过延续标记和换行符。)
请注意,除了最后一行之外的每一行都有一个连续标记(一个尾部反斜杠)。我们可以在上面的文本中加入这些内容,但这会使您无法准确使用要插入的文本。
相反,当我们将shell变量插入sed
命令时,我们将使用全局搜索和替换语法插入反斜杠:
# The following works with bash 4.3 and up
sed -i.bak "/^import re/a \
${lines_to_insert//$'\n'/$'\\\n'}
" sed-insertlines.txt
# Prior to v4.3, quoting worked differently in replacement
# patterns, and there was a bug with `$'...'` quoting. The
# following will work with all bashes I tested (starting with v3.2):
nl=$'\n' bsnl=$'\\\n'
sed -i.bak "/^import re/a \
${lines_to_insert//$nl/$bsnl}
" sed-insertlines.txt
另一个解决方案是使用mapfile命令将行读入数组:
mapfile -t lines_to_insert <<'EOF'
def string_cleanup(x, notwanted):
for item in notwanted:
x = re.sub(item, '', x)
return x
EOF
现在我们可以使用printf添加反斜杠:
sed -i.bak "/^import re/a \
$(printf '%s\\\n' "${lines_to_insert[@]}")
" sed-insertlines.txt
(搜索和替换语法也适用于数组,但我认为printf命令更具可读性。)
不幸的是,在文本之后添加了一个额外的换行符,因为原始文本中的所有行都是继续的。如果这是不希望的,可以通过在printf的开头而不是结尾处插入反斜杠和换行符,在第二个解决方案中轻松删除它,使得命令稍微不易读取:
sed -i.bak "/^import re/a $(printf '\\\n%s' "${lines_to_insert[@]}")
" sed-insertlines.txt
最后,基于Benjamin W的一个很好的答案,这里有一个使用sed r
命令和进程替换的版本(以避免临时文件):
sed '/^import re/r '<(cat<<'EOF'
def string_cleanup(x, notwanted):
for item in notwanted:
x = re.sub(item, '', x)
return x
EOF
) sed-insertlines.txt
答案 1 :(得分:3)
我会使用sed r
命令,它在当前周期之后插入文件的内容:
#!/bin/bash
# Write code to be inserted into 'insertfile' with proper indentation
cat <<'EOF' > insertfile
def string_cleanup(x, notwanted):
for item in notwanted:
x = re.sub(item, '', x)
return x
EOF
# Sed with r command
sed -i '/import re # Regular Expression library/r insertfile' sed-insertlines.txt
# Remove temp file
rm -f insertfile
导致
import re # Regular Expression library
def string_cleanup(x, notwanted):
for item in notwanted:
x = re.sub(item, '', x)
return x
def string_replace(i_string, pattern, newpattern):
string_corrected = re.sub(pattern, newpattern, i_string)
return string_corrected
答案 2 :(得分:1)
如果您有兴趣,可以使用Awk解决方案:
<强> python_file:强>
#!/bin/python
import re # Regular Expression library
def string_replace(i_string, pattern, newpattern):
string_corrected = re.sub(pattern, newpattern, i_string)
return string_corrected
我们的剧本
#!/bin/bash
read -rd '' lines_to_insert << 'EOF'
def string_cleanup(x, notwanted):
for item in notwanted:
x = re.sub(item, '', x)
return x
EOF
awk -v from_shell="$lines_to_insert" '
{
if ($0 ~ /import re # Regular Expression library/){
printf "%s\n%s\n",$0,from_shell
}
else{
print $0
}
}' python_file
<强>输出:强>
#!/bin/python
import re # Regular Expression library
def string_cleanup(x, notwanted):
for item in notwanted:
x = re.sub(item, '', x)
return x
def string_replace(i_string, pattern, newpattern):
string_corrected = re.sub(pattern, newpattern, i_string)
return string_corrected
注意:
我已从\n
删除了$lines_to_insert
。