shell while循环后变量的值未变化

 工作中想遍历文件中的每行,并且赋值给一个变量,使用下面写法,但是循环遍历后变量依然为空,值没有变化。如下:

~/temp/201908/temp/temp$ cat temp.txt
http://www.baidu.com
http://www.jd.com
http://www.huawei.com
~/temp/201908/temp/temp$ cat temp.sh
#! /bin/bash
file_path=temp.txt
new_var=''
cat ${file_path} | while read line
do
    new_var="${new_var}${line};"
    echo ${line}_____
done
echo "${new_var}+++++"
~/temp/201908/temp/temp$ source temp.sh
http://www.baidu.com_____
http://www.jd.com_____
http://www.huawei.com_____
+++++

上面未赋值成功是因为使用了管道符,将值传给了while,使得while在子shell中执行,子shell中的变量等在循环外无效。

可以写为:

~/temp/201908/temp/temp$ cat temp.sh
#! /bin/bash
file_path=temp.txt
new_var=''
while read line
do
    new_var="${new_var}${line};"
    echo ${line}_____
done <<< "$(cat ${file_path})"
echo "${new_var}+++++"
~/temp/201908/temp/temp$ source temp.sh
http://www.baidu.com_____
http://www.jd.com_____
http://www.huawei.com_____
http://www.baidu.com;http://www.jd.com;http://www.huawei.com;+++++

或者:

~/temp/201908/temp/temp$ cat temp.sh
#! /bin/bash
file_path=temp.txt
new_var=''
while read line
do
    new_var="${new_var}${line};"
    echo ${line}_____
done < ${file_path}
echo "${new_var}+++++"
~/temp/201908/temp/temp$ source temp.sh
http://www.baidu.com_____
http://www.jd.com_____
http://www.huawei.com_____
http://www.baidu.com;http://www.jd.com;http://www.huawei.com;+++++

参考:https://www.cnblogs.com/f-ck-need-u/p/7431578.html

<think>嗯,用户问的是关于shell脚本中while循环变量丢失的问题。我得先回想一下这个问题的常见原因和解决方法。记得在shell中,当使用管道将命令的输出传递给while循环时,循环实际上是在一个子shell中执行的。这样的话,在子shell中对变量的修改不会影响到父shell中的变量,导致循环结束后变量看起来“丢失”了。 那应该怎么解决呢?首先,可能需要避免使用管道,改用输入重定向。例如,使用重定向符号<将文件内容传递给while循环,而不是用管道。或者,可以考虑使用进程替换,比如在bash中用< <(command)的形式,这样循环不会在子shell中运行了。 另外,还有一种方法是使用here-string,将变量内容直接传递给循环。比如,把命令的输出保存到一个变量中,然后用here-string重定向进去。不过这样可能对大文件不太友好,因为会把所有内容加载到内存里。 然后,可能还要注意不同shell的兼容性。比如,在bash中可以通过shopt -s lastpipe设置,使得在非交互式shell中最后一个管道命令在父shell中执行,这样变量不会丢失了。不过这可能只在某些版本的bash中有效,需要用户根据自己的环境调整。 还有,用户可能需要例子来理解具体的解决方法。比如展示一个使用管道的错误例子,然后给出用重定向或进程替换的正确写法。同时提醒他们注意变量作用域的问题,以及在处理大文件时的内存考虑。 总结一下,回答的时候应该分步骤解释问题原因,然后给出几种解决方法,并说明各自的优缺点。确保用户能够根据实际情况选择最合适的解决方案。还要检查是否有遗漏的情况,比如不同的shell可能会有不同的行为,或者是否有其他方法可以解决变量丢失的问题,比如使用临时文件或者命名管道。不过这些方法可能稍微复杂,可能不太常用,但可以作为备选方案提及。</think>在Shell脚本中使用`while`循环时,变量“丢失”是常见问题,通常与子Shell(subshell)的作用域有关。以下是逐步分析和解决方法: --- ### **问题原因** 当`while`循环通过**管道**(`|`)接收输入时,循环体会在一个独立的子Shell中执行。子Shell中的变量修改**不会影响父Shell**,导致循环结束后变量看似“丢失”。 **错误示例**: ```bash #!/bin/bash count=0 # 使用管道触发子Shell cat file.txt | while read line; do ((count++)) # 在子Shell中修改count done echo "Total lines: $count" # 输出 Total lines: 0 ``` --- ### **解决方法** #### 方法1:避免管道,改用输入重定向 将输入通过**文件重定向**传递,而非管道: ```bash count=0 while read line; do ((count++)) done < file.txt # 重定向输入,避免子Shell echo "Total lines: $count" # 正确输出 ``` --- #### 方法2:使用进程替换(Bash特有) 通过`< <(...)`语法将命令输出重定向到循环: ```bash count=0 while read line; do ((count++)) done < <(cat file.txt) # 进程替换 echo "Total lines: $count" # 正确输出 ``` --- #### 方法3:使用临时变量或文件 若必须使用管道,可将结果保存到临时变量或文件: ```bash # 使用临时变量(适用于小文件) content=$(cat file.txt) count=0 while read line; do ((count++)) done <<< "$content" # here-string传递内容 echo "Total lines: $count" # 或使用临时文件 cat file.txt > tmp.txt count=0 while read line; do ((count++)) done < tmp.txt rm tmp.txt ``` --- #### 方法4:启用`lastpipe`(Bash 4.2+) 在非交互式Shell中,通过`shopt -s lastpipe`让最后一个管道命令在父Shell执行: ```bash #!/bin/bash shopt -s lastpipe # 启用lastpipe count=0 cat file.txt | while read line; do ((count++)) done echo "Total lines: $count" # 正确输出(需Bash 4.2+) ``` --- ### **关键总结** 1. **子Shell陷阱**:管道`|`会触发子Shell,导致变量隔离。 2. **替代方案**:优先使用输入重定向(`<`)、进程替换(`< <(...)`)或`lastpipe`。 3. **性能注意**:临时变量(如`$(...)`)会加载全部内容到内存,大文件需谨慎。 通过调整输入方式或作用域管理,可有效解决变量丢失问题。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值