替换文件中的环境变量:awk 还是 sed?

发布于 2024-11-05 08:42:53 字数 1884 浏览 5 评论 0原文

我有一个在 shell 脚本中获取的环境变量文件,例如:

# This is a comment
ONE=1
TWO=2
THREE=THREE
# End

在我的脚本中,我将该文件(假设它称为“./vars”)获取到当前环境中,并根据以下内容更改(部分)变量:用户输入。例如:

#!/bin/sh
# Read variables
source ./vars
# Change a variable
THREE=3
# Write variables back to the file??
awk 'BEGIN{FS="="}{print $1=$$1}' <./vars >./vars

如您所见,我一直在尝试使用 awk 来写回变量,sed 也是如此。没有成功。脚本的最后一行失败。有没有办法用 awk 或 sed 来做到这一点(最好保留注释,甚至带有“=”字符的注释)?或者我应该将“读取”与 while 循环中的字符串切割或其他魔法结合起来?如果可能的话,我想避免使用 perl/python,而只使用 Busybox 中提供的工具。非常感谢。

编辑:也许一个用例可以清楚地说明我的问题是什么。我保留一个由 shell 环境变量声明组成的配置文件:

# File: network.config
NETWORK_TYPE=wired
NETWORK_ADDRESS_RESOLUTION=dhcp
NETWORK_ADDRESS=
NETWORK_ADDRESS_MASK=

我还有一个名为“setup-network.sh”的脚本:

#!/bin/sh
# File: setup-network.sh

# Read configuration
source network.config

# Setup network
NETWORK_DEVICE=none
if [ "$NETWORK_TYPE" == "wired" ]; then
  NETWORK_DEVICE=eth0
fi
if [ "$NETWORK_TYPE" == "wireless" ]; then
  NETWORK_DEVICE=wlan0
fi
ifconfig -i $NETWORK_DEVICE ...etc

我还有一个名为“configure-network.sh”的脚本:

#!/bin/sh
# File: configure-network.sh

# Read configuration
source network.config

echo "Enter the network connection type:"
echo "  1. Wired network"
echo "  2. Wireless network"
read -p "Type:" -n1 TYPE

if [ "$TYPE" == "1" ]; then
  # Update environment variable
  NETWORK_TYPE=wired
elif [ "$TYPE" == "2" ]; then
  # Update environment variable
  NETWORK_TYPE=wireless
fi

# Rewrite configuration file, substituting the updated value
# of NETWORK_TYPE (and any other updated variables already existing
# in the network.config file), so that later invocations of
# 'setup-network.sh' read the updated configuration.
# TODO

如何重写配置文件,仅更新配置文件中已经存在的变量,最好保留注释和空行完好无损?希望这能让事情澄清一点。再次感谢。

I have a file of environment variables that I source in shell scripts, for example:

# This is a comment
ONE=1
TWO=2
THREE=THREE
# End

In my scripts, I source this file (assume it's called './vars') into the current environment, and change (some of) the variables based on user input. For example:

#!/bin/sh
# Read variables
source ./vars
# Change a variable
THREE=3
# Write variables back to the file??
awk 'BEGIN{FS="="}{print $1=$1}' <./vars >./vars

As you can see, I've been experimenting with awk for writing the variables back, sed too. Without success. The last line of the script fails. Is there a way to do this with awk or sed (preferably preserving comments, even comments with the '=' character)? Or should I combine 'read' with string cutting in a while loop or some other magic? If possible, I'd like to avoid perl/python and just use the tools available in Busybox. Many thanks.

Edit: perhaps a use case might make clear what my problem is. I keep a configuration file consisting of shell environment variable declarations:

# File: network.config
NETWORK_TYPE=wired
NETWORK_ADDRESS_RESOLUTION=dhcp
NETWORK_ADDRESS=
NETWORK_ADDRESS_MASK=

I also have a script called 'setup-network.sh':

#!/bin/sh
# File: setup-network.sh

# Read configuration
source network.config

# Setup network
NETWORK_DEVICE=none
if [ "$NETWORK_TYPE" == "wired" ]; then
  NETWORK_DEVICE=eth0
fi
if [ "$NETWORK_TYPE" == "wireless" ]; then
  NETWORK_DEVICE=wlan0
fi
ifconfig -i $NETWORK_DEVICE ...etc

I also have a script called 'configure-network.sh':

#!/bin/sh
# File: configure-network.sh

# Read configuration
source network.config

echo "Enter the network connection type:"
echo "  1. Wired network"
echo "  2. Wireless network"
read -p "Type:" -n1 TYPE

if [ "$TYPE" == "1" ]; then
  # Update environment variable
  NETWORK_TYPE=wired
elif [ "$TYPE" == "2" ]; then
  # Update environment variable
  NETWORK_TYPE=wireless
fi

# Rewrite configuration file, substituting the updated value
# of NETWORK_TYPE (and any other updated variables already existing
# in the network.config file), so that later invocations of
# 'setup-network.sh' read the updated configuration.
# TODO

How do I rewrite the configuration file, updating only the variables already existing in the configuration file, preferably leaving comments and empty lines intact? Hope this clears things up a little. Thanks again.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

可是我不能没有你 2024-11-12 08:42:53

您不能使用 awk 并从同一文件中读取和写入(这是您问题的一部分)。

我更喜欢在重写之前重命名该文件(但您也可以保存到 tmp,然后也重命名)。

/bin/mv file file.tmp
awk '.... code ...' file.tmp > file

如果您的 env 文件变大,您会发现它会根据操作系统的缓冲区大小被截断。

另外,不要忘记 gawk(大多数 Linux 安装上的 std)有一个内置数组 ENVIRON。您可以从中创建您想要的内容

awk 'END {
   for (key in ENVIRON) {
      print key "=" ENVIRON[key]
   }
}' /dev/null

当然,您可以获得环境中的所有内容,因此可能比您想要的更多。但可能是一个更好的地方来开始你想要完成的事情。

编辑
最具体的是

   awk -F"=" '{
     if ($1 in ENVIRON) {
         printf("%s=%s\n", $1, ENVIRON[$1])
     }
     # else line not printed or add code to meet your situation
   }' file > file.tmp
   /bin/mv file.tmp file

编辑2
我认为您的 var=values 可能需要 export -ed,以便它们对 awk ENVIRON 数组可见。

AND

echo PATH=xxx| awk -F= '{print ENVIRON[$1]}'

打印 PATH 的现有值。

我希望这有帮助。

PS,由于您似乎是新用户,如果您得到的答案对您有帮助,请记住将其标记为已接受,和/或给它 +(或 -)作为有用的答案。

You can't use awk and read and write from the same file (is part of your problem).

I prefer to rename the file before I rewrite (but you can save to a tmp and then rename too).

/bin/mv file file.tmp
awk '.... code ...' file.tmp > file

If your env file gets bigger, you'll see that is is getting truncated at the buffer size of your OS.

Also, don't forget that gawk (the std on most Linux installations) has a built in array ENVIRON. You can create what you want from that

awk 'END {
   for (key in ENVIRON) {
      print key "=" ENVIRON[key]
   }
}' /dev/null

Of course you get everything in your environment, so maybe more than you want. But probably a better place to start with what you are trying to accomplish.

Edit
Most specifically

   awk -F"=" '{
     if ($1 in ENVIRON) {
         printf("%s=%s\n", $1, ENVIRON[$1])
     }
     # else line not printed or add code to meet your situation
   }' file > file.tmp
   /bin/mv file.tmp file

Edit 2
I think your var=values might need to be export -ed so they are visible to the awk ENVIRON array.

AND

echo PATH=xxx| awk -F= '{print ENVIRON[$1]}'

prints the existing value of PATH.

I hope this helps.

P.S. as you appear to be a new user, if you get an answer that helps you please remember to mark it as accepted, and/or give it a + (or -) as a useful answer.

朮生 2024-11-12 08:42:53

我不完全知道你想做什么,但如果你想改变变量 THREE 的值,

awk -F"=" -vt="$THREE" '$1=="THREE" {$2=t}{print $0>FILENAME}' OFS="=" vars

I don't exactly know what you are trying to do, but if you are trying to change the value of variable THREE ,

awk -F"=" -vt="$THREE" '$1=="THREE" {$2=t}{print $0>FILENAME}' OFS="=" vars
过期以后 2024-11-12 08:42:53

您可以仅使用 bash 来执行此操作:

rewrite_config() {
    local filename="$1"
    local tmp=$(mktemp)

    # if you want the header
    echo "# File: $filename" >> "$tmp"

    while IFS='=' read var value; do
        declare -p $var | cut -d ' ' -f 3-
    done < "$filename" >> "$tmp"

    mv "$tmp" "$filename"
}

像使用临时文件一样使用它

source network.config
# manipulate the variables
rewrite_config network.config

来尽可能长时间地维护配置文件的存在。

You can do this in just with bash:

rewrite_config() {
    local filename="$1"
    local tmp=$(mktemp)

    # if you want the header
    echo "# File: $filename" >> "$tmp"

    while IFS='=' read var value; do
        declare -p $var | cut -d ' ' -f 3-
    done < "$filename" >> "$tmp"

    mv "$tmp" "$filename"
}

Use it like

source network.config
# manipulate the variables
rewrite_config network.config

I use a temp file to maintain the existance of the config file for as long as possible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文