在shell脚本中读取输入文件并将其行存储在变量中

时间:2015-04-14 14:08:02

标签: shell unix

我是UNIX新手并且遇到了这个非常简单的问题:

我有一个文本文件(input.txt),每行包含一个字符串。它看起来像这样:

House
Monkey
Car

在我的shell脚本中,我需要逐行读取此输入文件以获取这样的变量:

things="House,Monkey,Car"

我知道这听起来很简单,但我找不到任何简单的解决方案。到目前为止我最接近的尝试:

#!/bin/sh
things=""
addToString() {
    things="${things},$1"
}
while read line; do addToString $line ;done <input.txt
echo $things

但这不会奏效。关于我的谷歌研究,我认为while循环会创建一个新的子shell,但我错了(见评论部分)。然而,变量&#34;事物&#34;以后在回声中仍然没有。 (我不能只在while循环中写回声,因为我需要稍后使用该字符串)

你能帮帮我吗?任何帮助将不胜感激,谢谢!

4 个答案:

答案 0 :(得分:1)

这不是 shell 解决方案,但事实是纯shell中的解决方案通常过长且冗长。所以例如要进行字符串处理,最好使用属于“默认”Unix环境的特殊工具。

sed ':b;N;$!bb;s/\n/,/g' < input.txt

如果你想省略空行,那么:

sed ':b;N;$!bb;s/\n\n*/,/g' < input.txt

说到你的解决方案,它应该可行,但你应该总是在适用的地方使用引号。例如。这对我有用:

things=""
while read line; do things="$things,$line"; done < input.txt
echo "$things"

(当然,此代码存在问题,因为它会输出一个前导逗号。如果您想跳过空行,只需添加if项检查。)

答案 1 :(得分:1)

你提出的建议工作正常!我在这里只做了两处修改:添加缺少的引号,并处理空字符串的情况。

things=""
addToString() {
    if [ -n "$things" ]; then
      things="${things},$1"
    else
      things="$1"
    fi
}
while read -r line; do addToString "$line"; done <input.txt
echo "$things"

如果你管道进入while read,这会创建一个子shell,这会占用你的变量。你没有管道 - 你正在进行<input.txt重定向。没有子shell,代码无需更改即可运行。


也就是说,有更好的方法可以将项目列表读入shell变量。在3.0之后的任何版本的bash:

IFS=$'\n' read -r -d '' -a things <input.txt  # read into an array
printf -v things_str '%s,' "${things[@]}"     # write array to a comma-separated string
echo "${things_str%,}"                        # print that string w/o trailing comma

...在bash 4上,第一行可以是:

readarray -t things <input.txt # read into an array

答案 2 :(得分:0)

这可能/可能不起作用,具体取决于您使用的shell。在我的Ubuntu 14.04 / x64上,它适用于bashdash

为了使其更可靠并且独立于shell的行为,您可以尝试使用()明确地将整个块放入子shell中。例如:

(
things=""
addToString() {
    things="${things},$1"
}
while read line; do addToString $line ;done 
echo $things
) < input.txt

P.S。你可以使用这样的东西来避免初始逗号。没有bash扩展(使用短路逻辑运算符而不是if来表示简短性):

test -z "$things" && things="$1" || things="${things},${1}"

或使用bash扩展程序:

things="${things}${things:+,}${1}"

P.P.S。我该怎么做:

tr '\n' ',' < input.txt | sed 's!,$!\n!'

答案 3 :(得分:0)

您也可以这样做:

#!/bin/bash
while read -r i
do
[[ $things == "" ]] && things="$i" || things="$things","$i"
done < <(grep . input.txt)
echo "$things"

输出:

House,Monkey,Car
  

N.B:

使用grep来处理空行以及文件末尾没有换行的可能性。 (如果文件末尾没有换行符,则普通while read将无法读取最后一行。)