Это потому, что в <<< $line
, bash
делает разделение слов, (хотя и не globbing) на $line
, так как там нет кавычек, а затем соединяет получившиеся слова символом пробела (и помещает это во временный файл, за которым следует символ новой строки, и делает это stdin для cut
).
$ a=a,b,,c bash -c 'IFS=","; sed -n l <<< $a'
a b c$
tab
оказывается в значении по умолчанию $IFS
:
$ a=$'a\tb' bash -c 'sed -n l <<< $a'
a b$
Решение в bash
- заключить переменную в кавычки.
$ a=$'a\tb' bash -c 'sed -n l <<< "$a"'
a\tb$
Обратите внимание, что это единственная оболочка, которая делает это. zsh
(откуда взялся <<<
, вдохновленный Unix-портом rc
), ksh93
, mksh
и yash
, которые также поддерживают <<<
, не делают этого.
Когда дело доходит до массивов, mksh
, yash
и zsh
соединяются по первому символу $IFS
, bash
и ksh93
по пробелу.
$ mksh -c 'a=(1 2); IFS=:; sed -n l <<< "${a[@]}"'
1:2$
$ yash -c 'a=(1 2); IFS=:; sed -n l <<< "${a[@]}"'
1:2$
$ ksh -c 'a=(1 2); IFS=:; sed -n l <<< "${a[@]}"'
1 2$
$ zsh -c 'a=(1 2); IFS=:; sed -n l <<< "${a[@]}"'
1:2$
$ bash -c 'a=(1 2); IFS=:; sed -n l <<< "${a[@]}"'
1 2$
Есть разница между zsh
/yash
и mksh
(версия R52, по крайней мере), когда $IFS
пуст:
$ mksh -c 'a=(1 2); IFS=; sed -n l <<< "${a[@]}"'
1 2$
$ zsh -c 'a=(1 2); IFS=; sed -n l <<< "${a[@]}"'
12$
Поведение более согласовано в разных оболочках, когда вы используете "${a[*]}"
(за исключением того, что mksh
все еще имеет ошибку, когда $IFS
пуст).
В echo $line | ...
, это обычный оператор split+glob во всех Bourne-подобных оболочках, кроме zsh
(и обычные проблемы, связанные с echo
).