Почему вы не можете использовать cat для чтения строки в строке, где каждая строка имеет разделители

У меня есть текстовый файл, который содержит что-то вроде этого:

abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma

Я написал сценарий

for i in 'cat file'
do
   echo $i
done

По какой-то причине вывод сценария не выводит файл по строкам, а прерывает его в запятых, а также в новой строке. Почему кошка или "для бла в cat xyz " делают это и как я могу сделать это НЕ делать это? Я знаю, что могу использовать

while read line
do
   blah balh blah
done < file

но я хочу знать, почему cat или "for blah in" делает это для дальнейшего понимания команд unix. Страница Cat man не помогла мне, и, глядя или зациклившись в руководстве bash, не было получено никаких ответов (http://www.gnu.org/software/bash/manual/bashref.html). Заранее спасибо за вашу помощь.

Ответ 1

Проблема не в cat, ни в петле for per se; он использует обратные кавычки. Когда вы пишете:

for i in 'cat file'

или лучше):

for i in $(cat file)

или (в bash):

for i in $(<file)

оболочка выполняет команду и фиксирует вывод как строку, разделяя слова на символы в $IFS. Если вы хотите, линии ввода в $i, вы должны либо возиться с IFS или использовать while цикл. В while петля лучше, если есть какая- либо опасность, что файлы будут обрабатываться большой; он не должен сразу читать весь файл в памяти, в отличие от версий с помощью $(...).

IFS='
'
for i in $(<file)
do echo "$i"
done

Котировки вокруг "$i" как правило, являются хорошей идеей. В этом контексте, с измененным $IFS, это на самом деле не критично, но хорошие привычки - хорошие привычки. Это имеет значение в следующем сценарии:

old="$IFS"
IFS='
'
for i in $(<file)
do
   (
   IFS="$old"
   echo "$i"
   )
done

когда файл данных содержит несколько пробелов между словами:

$ cat file
abc                  123,         comma
the   quick   brown   fox
jumped   over   the   lazy   dog
comma,   comma
$ 

Вывод:

$ sh bq.sh
abc                  123,         comma
the   quick   brown   fox
jumped   over   the   lazy   dog
comma,   comma
$

Без двойных кавычек:

$ cat bq.sh
old="$IFS"
IFS='
'
for i in $(<file)
do
   (
   IFS="$old"
   echo $i
   )
done
$ sh bq.sh
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
$

Ответ 2

Вы можете использовать переменную IFS для конкретной, которую вы хотите использовать в качестве разделителя полей:

IFS=$'\n'
for i in 'cat file'
do
   echo $i
done

Ответ 3

IFS. Внутренний разделитель полей может быть настроен так, чтобы получить то, что вы хотите.

Чтобы сразу прочитать целую строку, используйте: IFS = ""

Ответ 4

цикл цикла, связанный с изменением внутреннего разделителя полей (IFS), будет считывать файл по назначению

для ввода

abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma

Для цикла, связанного с изменением IFS

old_IFS=$IFS
IFS=$'\n'
for i in 'cat file'
do
        echo $i
done
IFS=$old_IFS

приводит к

abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma