Bash - 如何用变量中定义的多行替换以模式开头的单行?
Bash - how to replace a single line starting with a pattern with multiple lines defined in a variable?
我有一个文件,有时包含如下一行:
VIRTUAL_ENV="/afs/sern.ch/user/l/lronhubbard/virtual_environment"
这是文件中唯一以 VIRTUAL_ENV
开头的行。使用脚本,我想用以下几行替换这一行:
directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
directory_env="$(dirname "${directory_bin}")"
VIRTUAL_ENV="${directory_env}"
这是怎么做到的?
首先,我将替换行存储在脚本的此处文档中:
IFS= read -d '' text << "EOF"
directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
directory_env="$(dirname "${directory_bin}")"
VIRTUAL_ENV="${directory_env}"
EOF
接下来,我可以使用 sed
:
将文件中的行替换为其他内容(此处为 xxx
)
sed -i "s/^VIRTUAL_ENV.*/xxx/g" test.txt
现在,我如何使用此处定义的文档变量 ${text}
,及其所有换行符和诸如此类的东西,而不是 sed
命令中的 xxx
?
编辑:根据 rslemos 的建议,我使用临时文件而不是此处文档实现了以下内容:
#!/bin/bash
temporary_filename="$(tempfile)"
cat > "${temporary_filename}" << "EOF"
directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
directory_env="$(dirname "${directory_bin}")"
VIRTUAL_ENV="${directory_env}"
EOF
sed -i "/^VIRTUAL_ENV.*/ {
r ${temporary_filename}
d
}" test.txt
rm "${temporary_filename}"
我还是想知道如何直接使用这里的文档,这样我就不会不必要地使用硬盘了。
我会和 sed
一起去:
/^VIRTUAL_ENV/{
r source.txt
d
}
其中 source.txt 是新行所在的文件,用于替换以 "VIRTUAL_ENV" 开头的行。
如果您真的需要新行 (source.txt) 作为此处的文档,/dev/fd/0
技巧将起作用(至少在 Linux 中)。但你也可以组合 mktemp
和 mkfifo
.
编辑
解决“我仍然想知道如何直接使用此处文档”的问题:
!/bin/bash
sed -e '/^VIRTUAL_ENV/{' -e 'r /dev/fd/0' -ed -e'}' test.txt << "EOF"
directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
directory_env="$(dirname "${directory_bin}")"
VIRTUAL_ENV="${directory_env}"
EOF
不太便携,因为 /dev/fd/0
部分(虽然在 Linux 中有效)。
sed
的许多方言允许您在替换中转义换行符:
sed -i 's/^VIRTUAL_ENV.*/directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"\
directory_env="$(dirname "${directory_bin}")"\
VIRTUAL_ENV="${directory_env}"/' test.txt
这是一个跨越三行的 single-quoted 字符串,在每个内部行边界处添加了一个反斜杠以继续。
这不能移植到所有 sed
变体,但至少在 *BSD(包括 OSX)和 Linux 上工作正常。
顺便说一句,您也可以简单地将所有这些命令放在一行中,它们之间用分号隔开。
这可能对你有用(GNU sed & bash):
cat <<\! | sed $'/PATTERN/{r /dev/stdin\n;d}' file
HERE DOCUMENT
STUFF
HERE
!
使用 cat
将 stdin
通过管道传输到 sed 命令中,并使用 r
命令将其作为文件读取。
N.B。 \!
引用此处文档中的所有文本,使用 !
插入变量。 $'...'
允许需要换行符的命令(即 sed 命令,例如 r
、a
、i
、c
、R
、w
,W
) 写成一行。
我有一个文件,有时包含如下一行:
VIRTUAL_ENV="/afs/sern.ch/user/l/lronhubbard/virtual_environment"
这是文件中唯一以 VIRTUAL_ENV
开头的行。使用脚本,我想用以下几行替换这一行:
directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
directory_env="$(dirname "${directory_bin}")"
VIRTUAL_ENV="${directory_env}"
这是怎么做到的?
首先,我将替换行存储在脚本的此处文档中:
IFS= read -d '' text << "EOF"
directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
directory_env="$(dirname "${directory_bin}")"
VIRTUAL_ENV="${directory_env}"
EOF
接下来,我可以使用 sed
:
xxx
)
sed -i "s/^VIRTUAL_ENV.*/xxx/g" test.txt
现在,我如何使用此处定义的文档变量 ${text}
,及其所有换行符和诸如此类的东西,而不是 sed
命令中的 xxx
?
编辑:根据 rslemos 的建议,我使用临时文件而不是此处文档实现了以下内容:
#!/bin/bash
temporary_filename="$(tempfile)"
cat > "${temporary_filename}" << "EOF"
directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
directory_env="$(dirname "${directory_bin}")"
VIRTUAL_ENV="${directory_env}"
EOF
sed -i "/^VIRTUAL_ENV.*/ {
r ${temporary_filename}
d
}" test.txt
rm "${temporary_filename}"
我还是想知道如何直接使用这里的文档,这样我就不会不必要地使用硬盘了。
我会和 sed
一起去:
/^VIRTUAL_ENV/{
r source.txt
d
}
其中 source.txt 是新行所在的文件,用于替换以 "VIRTUAL_ENV" 开头的行。
如果您真的需要新行 (source.txt) 作为此处的文档,/dev/fd/0
技巧将起作用(至少在 Linux 中)。但你也可以组合 mktemp
和 mkfifo
.
编辑
解决“我仍然想知道如何直接使用此处文档”的问题:
!/bin/bash
sed -e '/^VIRTUAL_ENV/{' -e 'r /dev/fd/0' -ed -e'}' test.txt << "EOF"
directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
directory_env="$(dirname "${directory_bin}")"
VIRTUAL_ENV="${directory_env}"
EOF
不太便携,因为 /dev/fd/0
部分(虽然在 Linux 中有效)。
sed
的许多方言允许您在替换中转义换行符:
sed -i 's/^VIRTUAL_ENV.*/directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"\
directory_env="$(dirname "${directory_bin}")"\
VIRTUAL_ENV="${directory_env}"/' test.txt
这是一个跨越三行的 single-quoted 字符串,在每个内部行边界处添加了一个反斜杠以继续。
这不能移植到所有 sed
变体,但至少在 *BSD(包括 OSX)和 Linux 上工作正常。
顺便说一句,您也可以简单地将所有这些命令放在一行中,它们之间用分号隔开。
这可能对你有用(GNU sed & bash):
cat <<\! | sed $'/PATTERN/{r /dev/stdin\n;d}' file
HERE DOCUMENT
STUFF
HERE
!
使用 cat
将 stdin
通过管道传输到 sed 命令中,并使用 r
命令将其作为文件读取。
N.B。 \!
引用此处文档中的所有文本,使用 !
插入变量。 $'...'
允许需要换行符的命令(即 sed 命令,例如 r
、a
、i
、c
、R
、w
,W
) 写成一行。