Как разделить список запятой, а не пробелом - PullRequest
42 голосов
/ 11 октября 2011

Я хочу разделить текст запятой ,, а не пробелом в 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?

Ответы [ 7 ]

48 голосов
/ 11 октября 2011

Set IFS to,

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:~$ 
45 голосов
/ 11 октября 2011

Использование подоболочки для анализа слов отменяет всю работу, которую вы выполняете, чтобы сложить пробелы.

Попробуйте вместо этого:

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

Это также увеличивает параллелизм.Использование подоболочки, как в вашем вопросе, заставляет завершить весь процесс подоболочки, прежде чем вы сможете начать перебирать ответы.Трубопровод к подоболочке (как в моем ответе) позволяет им работать параллельно.Конечно, это важно только в том случае, если в файле много строк.

17 голосов
/ 11 октября 2011

Я думаю, что канонический метод:

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
10 голосов
/ 11 октября 2011
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
7 голосов
/ 09 мая 2014

Создать функцию 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

(Обратите внимание, этот ответ был обновлен в соответствии с некоторыми отзывами)

5 голосов
/ 11 октября 2011

Чтение: http://linuxmanpages.com/man1/sh.1.php & http://www.gnu.org/s/hello/manual/autoconf/Special-Shell-Variables.html

IFS Внутренний разделитель полей, используемый для разделения слов после раскрытия и разбить строки на слова с прочитанным встроенная команда. Значением по умолчанию является `` ''.

IFS - это переменная среды оболочки, поэтому она останется неизменной в контексте вашего сценария оболочки, но не будет иначе, если вы не экспортируете ее. ТАКЖЕ ВНИМАНИЕ, что 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
0 голосов
/ 11 сентября 2017

Вы можете использовать:

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'
...