如何在Bash中连接文件中的所有行?

5

我有一个 csv 文件:

data1,data2,data2
data3,data4,data5
data6,data7,data8

我希望将其转换为(包含在一个变量中):

variable=数据1,数据2,数据2%0D%0A数据3,数据4,数据5%0D%0A数据6,数据7,数据8

我的尝试:

data=''
cat csv | while read line
do
data="${data}%0D%0A${line}"
done
echo $data  # Fails, since data remains empty (loop emulates a sub-shell and looses data)

请帮忙。。。

8个回答

21

更简单的方法是从文件中去除换行符:

tr '\n' '' < yourfile.txt > concatfile.txt

1
tr '\n' '' < csv 打印出值,就像你的原始脚本做的那样。如果你在bash中不需要将其存储为变量 - 听起来似乎是需要的 - 你完全可以放弃它。 - paulmelnikow
3
对我来说并没有“立即生效”,但是它让我找到了tr -d '\n'这个很好用的方法:谢谢! - Tomislav Nakic-Alfirevic

6
在bash中,
data=$(
while read line
do
  echo -n "%0D%0A${line}"
done < csv)

在非bash shell中,你可以使用 `...` 代替 $(...) 。另外, echo -n 可以抑制换行符,但不幸的是它不完全可移植,在bash中运行良好。

获取额外的空格:this,is,some,data%0D%0A this,is,again,data%0D%0A third,line,of,data%0D%0A fourth,line,in,data%0D%0A - Yugal Jindle
对了...哎呀。编辑以添加echo -n - Andrew Schulman
2
FYI,$()是标准的。已经使用多年了。如果您想要一个可移植的echo -n,请使用printf - sorpigal

4

有些答案非常复杂。这样怎么样。

 data="$(xargs printf ',%s' < csv | cut -b 2-)"

或者

 data="$(tr '\n' ',' < csv | cut -b 2-)"

对于您来说,这个“外部实用程序”太过复杂了吗?

IFS=$'\n', read -d'\0' -a data < csv

现在您有一个数组!您可以按照自己的喜好输出它,例如使用

data="$(tr ' ' , <<<"${data[@]}")"

如果你觉得还是太过“外部化”,那好吧,

data="$(printf "${data[0]}" ; printf ',%s' "${data[@]:1:${#data}}")"

是的,printf可以成为内置命令。如果它不是但你的echo是,并且支持-n,那么请使用echo -n代替:

data="$(echo -n "${data[0]}" ; for d in "${data[@]:1:${#data[@]}}" ; do echo -n ,"$d" ; done)"

好的,现在我承认我有点傻了。Andrew的回答完全正确。


3

我更喜欢使用循环:

for line in $(cat file.txt); do echo -n $line; done

注意:此解决方案要求输入文件在文件末尾有换行符,否则会丢弃最后一行。

1
@Julien,你可以在文件名前加上“echo "" >> file.txt”。 - Alexandre Mélard
2
并非总是可以修改源文件。您也可以使用临时副本。无论如何,您的解决方案是有效的;只是值得提到它的限制或陷阱。 - Julien Carsique

2

另一个简短的Bash解决方案

variable=$(
  RS=""
  while read line; do
    printf "%s%s" "$RS" "$line"
    RS='%0D%0A'
  done < filename
)

1
awk 'END { print r }
{ r = r ? r OFS $0 : $0 }
  ' OFS='%0D%0A' infile  

使用 shell

data=

while IFS= read -r; do
  [ -n "$data" ] &&
     data=$data%0D%0A$REPLY ||
    data=$REPLY
done < infile

printf '%s\n' "$data"   

最近的 bash 版本:

data=

while IFS= read -r; do
  [[ -n $data ]] &&
     data+=%0D%0A$REPLY ||
    data=$REPLY
done < infile

printf '%s\n' "$data"

1
一个非常简单的单行解决方案,不需要额外的文件,因为它相当容易理解(我认为,只需将文件连接在一起并执行sed替换):
output=$(echo $(cat ./myFile.txt) | sed 's/ /%0D%0A/g')

0

滥用 cat 是要受惩罚的!你需要将 CSV 喂入循环中。

while read line; do 
 # ...
done < csv

获取额外的空格:this,is,some,data%0D%0A this,is,again,data%0D%0A third,line,of,data%0D%0A fourth,line,in,data%0D%0A - Yugal Jindle
有趣,我不知道。它们是在源文件中还是你的 shell 表达式中? - themel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接