IFS=$'\n' doesn't change IFS to breakl

2019-08-07 02:11发布

I wrote the next test shell script:

#!/bin/sh
IFS=$'\n'
for d in `find . -name *.cue -print0 | xargs -0 -n1 dirname | sort --unique`
do
  unset IFS
  echo "$d"
  IFS=$'\n'
done
unset IFS

If I execute the find command of the condition in the bash I obtain something like this:

./[FLAC] Destination Goa - The Sixth Chapter (CD)/CD2
./[FLAC] Eat Static - Implant - (CD)
./[FLAC] Elysium - Dance For The Celestial Beings (CD)
./[FLAC] Elysium - Monzoon 1996 (CD)
./[FLAC] Etnica - The Juggeling Alchemists Under The Black Light

(the name of the folders containing cue files)

In the shell script I want to loop using each one of this folders but, of course, if I don't redefine the IFS the occurreances breaks with spaces:

Experience
4
./[FLAC]
VA
-
Trancentral
Five
A
Sonic
Initiation
./[FLAC]
VA
-
Trancentral

In other computer (a MacOS) I solved this problem changing the IFS to breaklines with this command IFS=$'\n' but in my home computer (an Ubuntu Linux) the loop breaks occurrences with "n":

tra
ce - A Trip To Psychedelic Tra
ce (CD)/CD1
./[FLAC] VA - Ta
tra
ce - A Trip To Psychedelic Tra
ce (CD)/CD2
./[FLAC] VA - Tech
o Tra
ce Ma

Do you know what's happening and why the different behaviour between computers? Thank you.

标签: shell
2条回答
\"骚年 ilove
2楼-- · 2019-08-07 02:16

You don't need the loop at all. This should do what you want:

find . -name *.cue -print0 | xargs -0 -n1 dirname | sort --unique

If you really want to loop over the results, you should use while rather than for:

while IFS= read -r line; do
    printf '%s\n' "$line"
done < "$file"

or

my_script | while IFS= read -r line; do
    printf '%s\n' "$line"
done

Going back to the question about splitting on a literal n character, it could be that /bin/sh on your Ubuntu machine doesn't support the $'' bashism.

查看更多
We Are One
3楼-- · 2019-08-07 02:32

You can set IFS to to a newline like this:

IFS="
"

$'\n' is ksh93/bash/zsh syntax but it is not POSIX syntax. On most current systems #!/bin/sh points to a POSIX shell (although this is not demanded by POSIX and Solaris 9,10 is an exception).

Whether that shell happens to understand $'\n' is not something you should rely on. If you want to use $'\n' change you shebang to #!/bin/bash or one of the other shells..


On Ubuntu and debian linux and derivatives /bin/sh points to dash . With some other distributions it points to /bin/bash --posix (bash in posix mode)...


Another point to note is that if you unset IFS you are not returning to the previous state, which is IFS that contains a space, a TAB and a newline. By unsetting IFS , field splitting will be done as if IFS contains a space, a TAB and a newline, so all seems well.

Unsetting IFS can give complications, however, if this is mixed with the regular practice

  unset IFS        # Unset the IFS variable so it does not exist
  oldIFS=$IFS      # The old state is supposedly saved
  IFS=:            # IFS is set to some string
  IFS=$oldIFS      # Now IFS is set to the empty string, which means no field 
                   # splitting is performed at all
查看更多
登录 后发表回答