如何用逗号而不是空格分割列表

Posted

技术标签:

【中文标题】如何用逗号而不是空格分割列表【英文标题】:How to split a list by comma not space 【发布时间】:2011-12-04 19:42:54 【问题描述】:

我想在for foo in list 中用逗号, 而不是空格 分割文本。假设我有一个 CSV 文件 CSV_File,其中包含以下文本:

Hello,World,Questions,Answers,bash shell,script
...

我使用以下代码将其拆分为几个单词:

for word in $(cat CSV_File | sed -n 1'p' | tr ',' '\n')
do echo $word
done

打印出来:

Hello
World
Questions
Answers
bash
shell
script

但我希望它用逗号而不是空格分隔文本:

Hello
World
Questions
Answers
bash shell
script

如何在 bash 中实现这一点?

【问题讨论】:

@Carl 你能提供一个使用awk的例子吗? 【参考方案1】:

使用 subshel​​l 替换来解析单词会撤消您将空格放在一起所做的所有工作。

试试吧:

cat CSV_file | sed -n 1'p' | tr ',' '\n' | while read word; do
    echo $word
done

这也增加了并行性。在您的问题中使用子外壳会强制整个子外壳过程完成,然后您才能开始迭代答案。管道到子外壳(如我的回答)让它们并行工作。当然,这仅在文件中有很多行时才重要。

【讨论】:

是的,这比我建议的要好得多。 +1 l33t bash 技能 mkj :) 甚至不需要while循环。 目前不需要while循环,但我理解echo的调用作为一些更有趣命令的代理;也就是说,OP 希望 shell 变量中的多字 CSV 内容与其他一些任意命令一起使用。这就是为什么我使用 read 来演示如何将内容放入 shell 变量中。 请注意,如果输入包含换行符,这将无法按预期工作(然后它将在逗号 最初出现在输入中的换行符上拆分,即 @987654325 @ 将被拆分为 4 个字段,而不是所需的 3)。对于 Bash,我建议使用单命令范围的 IFS 设置与 read -aread -d(参见 proper IFS setting in Bash)结合使用,但对于 POSIX shell,我发现 substring processing 是唯一干净且愚蠢的-证明解决方案。【参考方案2】:

将IFS 设置为,:

sorin@sorin:~$ IFS=',' ;for i in `echo "Hello,World,Questions,Answers,bash shell,script"`; do echo $i; done
Hello
World
Questions
Answers
bash shell
script
sorin@sorin:~$ 

【讨论】:

不错!我完全忘记了 IFS 环境变量! 要在脚本中使用它,您应该将 IFS 变量恢复为之前的值。请参阅 Andrew Newdigate 的回答。 @Sorin:通过“在脚本中使用它”,我的意思是需要更多的代码而不只是这个,因此您希望重置 IFS 以避免任何意外行为。 IFS 的含义似乎相当广泛,所以最好是懒惰而不是不清楚。顺便提一句。如果你像你的答案一样运行你的命令,它会改变当前环境的 IFS,你很容易忘记这一点,然后想知道为什么你的 shell 表现得如此奇怪。【参考方案3】:

我认为规范的方法是:

while IFS=, read field1 field2 field3 field4 field5 field6; do 
  do stuff
done < CSV.file

如果你不知道或不在乎有多少字段:

IFS=,
while read line; do
  # split into an array
  field=( $line )
  for word in "$field[@]"; do echo "$word"; done

  # or use the positional parameters
  set -- $line
  for word in "$@"; do echo "$word"; done

done < CSV.file

【讨论】:

非常方便,可以按名称引用特定字段 @glenn-jackman 你是对的,规范的 UNIX 会使用你的第一种方法。第二个仅适用于 bash 或 zsh 的现代实现。 bash 的 read 命令有一个 -a 选项,可以将行中的单词读入数组:while read -a words; do for word in "$words[@]" ...【参考方案4】:
kent$  echo "Hello,World,Questions,Answers,bash shell,script"|awk -F, 'for (i=1;i<=NF;i++)print $i'
Hello
World
Questions
Answers
bash shell
script

【讨论】:

我假设echo $word 实际上并不是真正需要使用 $word 完成的事情。在这种情况下,您的 awk expession 是在原始问题中执行 sed 和 tr 的另一种方法。我认为 Eng.Fouad 希望在 shell 变量中使用空格的值来做其他事情。 @mkj 此解决方案可以进一步用作 shell 变量,例如:FOO="Hello,World,Questions,Answers,bash shell,script"; BOO=$(echo $FOO | awk -F, 'for (i=1;i&lt;=NF;i++)print $i'); for B in $BOO; do echo "&lt;$B&gt;"; done @RomanChernyatchik $BOO 上的循环为“bash”和“shell”产生了单独的变量,因此无法按 OP 的预期工作【参考方案5】:

创建一个 bash 函数

split_on_commas() 
  local IFS=,
  local WORD_LIST=($1)
  for word in "$WORD_LIST[@]"; do
    echo "$word"
  done


split_on_commas "this,is a,list" | while read item; do
  # Custom logic goes here
  echo Item: $item
done

...这会生成以下输出:

Item: this
Item: is a
Item: list

(注意,这个答案已经根据一些反馈进行了更新)

【讨论】:

很奇怪。知道为什么会发生这种情况吗? 副作用在这里解释superuser.com/questions/781766/ifs-separated-items-in-loop 为避免“副作用”,首先将 IFS var 存储在某处OLDIFS=$IFS,然后执行IFS=, sentences1=($sentences),最后恢复 IFS:IFS=$OLDIFS。否则,这就是我正在寻找的答案。谢谢。 @clime 和 Val,我已更新我的答案以考虑您的反馈。它似乎运作良好,但请告诉我您的想法。 我觉得你的帖子现在太复杂了。修复原始代码 sn-p 并在最后通过一个小注释向评论员致谢就足够了;)。但无论如何,没有什么是完美的。【参考方案6】:

阅读:http://linuxmanpages.com/man1/sh.1.php &http://www.gnu.org/s/hello/manual/autoconf/Special-Shell-Variables.html

IFS 用于分词的内部字段分隔符 展开后,用 read 将行拆分成单词 内置命令。默认值为“”。

IFS 是一个 shell 环境变量,所以它在你的 shell 脚本的上下文中保持不变,除非你导出它。还要注意,IFS 根本不可能从您的环境继承:请参阅此 gnu 帖子了解原因和有关 IFS 的更多信息。

你的代码是这样写的:

IFS=","
for word in $(cat tmptest | sed -n 1'p' | tr ',' '\n'); do echo $word; done;

应该可以,我在命令行上测试过。

sh-3.2#IFS=","
sh-3.2#for word in $(cat tmptest | sed -n 1'p' | tr ',' '\n'); do echo $word; done;
World
Questions
Answers
bash shell
script

【讨论】:

【参考方案7】:

你可以使用:

cat f.csv | sed 's/,/ /g' |  awk 'print $1 " / " $4'

echo "Hello,World,Questions,Answers,bash shell,script" | sed 's/,/ /g' |  awk 'print $1 " / " $4'

这是用空格代替逗号的部分

sed 's/,/ /g'

【讨论】:

以上是关于如何用逗号而不是空格分割列表的主要内容,如果未能解决你的问题,请参考以下文章

如何用逗号分割不跟空格的字符串?

如何用逗号分割字符串而不在perl的引号内包含逗号?

如何用括号外的逗号分割字符串?

如何用空格分割字符串,不包括Python中双引号之间的空格? [复制]

JAVA 如何用部分空格分割字符串,急!

如何用逗号分割行并在 PostgreSQL 中取消透视表?