18000

[code]

    $ cat ~/tmp/test.txt
    banana 100 abc
    apple  200 xyz
    
    $ for i in `cat ~/tmp/test.txt`;do echo $i;done
    banana
    100
    abc
    apple
    200
    xyz
    
    $export IFS="\n"
    $for i in `cat ~/tmp/test.txt`;do echo $i; done
    ba
    a
    a 100 abc
    apple 200 xyz
    
[/code]

タブ区切りのレコードを１行単位で取り出して処理したいのですが、見ての通りシェルのフィールドセパレータを`"\n"`とするだけでは文字の`"n"`も区切り文字となってしまいます。  
意図通りに改行のみで区切るにはどうしたらいいのでしょうか。  
上記は`ubuntu
15.04`で動作させたため`bash`を使ってますが、できればOS間で共通に動作するシェルスクリプトに応用したいので、`/bin/sh`でも扱える方法が分ると嬉しいです。

利用環境：  
ubuntu 15.04  
freebsd 10.2-stable  
centos 6.7


CC BY-SA 3.0
2015-10-23T22:36:14.923
17999
2015-10-24T17:07:27.440
9403
question
sh shellscript
IFSに改行のみを指定したい


for ループで処理するのであれば、

[code]

    $ IFS='
    '
    $ for i in `cat ~/tmp/test.txt`;do printf '%s\n' "$i"; done
    
[/code]

とします。`IFS` に改行(0x0a)を指定するには改行をそのままの形で入力します。なお、`bash` や `zsh` であれば `$'\n'`
といった記法が使用できます。

ここで、`echo` ではなく、`printf` を使う様に変更したのは理由があります。Debian 系 Linux の `/bin/sh`(実体は
`/bin/dash`)に限らず、以下の様な問題があるからです。

**test.txt**

[code]

        banana  \100    abc
    -n
    apple   200 xyz
    
[/code]

**echo による処理**

[code]

    $ IFS='
    '
    $ for i in `cat ~/tmp/test.txt`;do echo "$i"; done
        banana  \100    abc
    apple   200 xyz
    
[/code]

2行目の `-n` が抜け落ちてしまいました。これは、

[code]

    echo "$i" => echo "-n" => echo -n
    
[/code]

と解釈されたためです。`printf`(`bash/zsh/dash` では shell builtin
function)の場合はこの様な問題は発生しません。

※ 以下は削除  
~~  
ただ、一部の sh ではバックスラッシュ文字が問題になります(例えば Ubuntu Linux の`/bin/sh`(実体は `/bin/dash`)。

**test.txt**

[code]

        banana  \100    abc
    apple   200 xyz
    
[/code]

**/bin/dash on Ubuntu Linux**

[code]

    $ IFS='
    '
    $ for i in `cat ~/tmp/test.txt`;do echo "$i"; done
    
        banana  @   abc
    apple   200 xyz
    
[/code]

**追記**

Tatz Sekine さんからのコメントで、`/bin/echo` を使うとバックスラッシュ文字はそのまま出力できます(`echo` は `builtin
function`)。

[code]

    $ IFS='
    '
    $ for i in `cat ~/tmp/test.txt`;do /bin/echo "$i"; done
    
        banana  \100    abc
    apple   200 xyz
    
[/code]

なお、`dash` の `printf`(builtin function)ではバックスラッシュ文字の問題はありません。

[code]

    printf '%s\n' "$i"
    
[/code]

~~


CC BY-SA 3.0
2015-10-24T00:04:33.077
18000
2015-10-24T17:07:27.440
2015-10-24T17:07:27.440
17999
answer


IFS='^M'

^M = Ctrl+Vを押してからEnterKey  
としてはダメですか？


CC BY-SA 3.0
2015-10-24T00:11:52.640
18001
2015-10-24T00:11:52.640
12936
17999
answer


「IFSに改行のみを指定したい」への直接の回答ではないですが、もし入力が tsv なら

[code]

    IFS='    
    '  # TAB (^I) と改行 $'\t\n'
    while read -r item price comment; do
        /bin/echo "$item" "$price" "$comment"
    done < ~/tmp/test.txt
    
[/code]

という形で書いておけば、カラムごとにパースするのに IFS を戻す必要がありません。


CC BY-SA 3.0
2015-10-24T00:39:42.270
18002
2015-10-24T00:39:42.270
2521
17999
answer


1行単位で処理するのであれば、for ではなく while と read を使った方がいいと思います。

[code]

    (1行を変数に)
    export IFS=$(echo -en '\t')
    while read -r line ; do echo "$line" ; done < test.txt
    
    (カラムごと変数に:その1)
    export IFS=$(echo -en '\t')
    while read -r a b c others ; do echo "$a" ; echo "$b" ; echo "$c" ; done < test.txt
    
    (カラムごと変数に:その2)
    export IFS=$(echo -en '\t')
    while read -r -a arg ; do echo "${arg[0]}" ; echo "${arg[1]}" ; echo ${arg[2]}"; done < test.txt
    
[/code]


CC BY-SA 3.0
2015-10-24T00:53:07.963
18003
2015-10-24T15:15:38.210
2015-10-24T15:15:38.210
4603
4603
17999
answer