Skip to main content
added 503 characters in body
Source Link
Stéphane Chazelas
  • 553.6k
  • 92
  • 1.1k
  • 1.6k
function join1 {
    typeset IFS=,      # typeset makes a local variable in ksh²
    print -r -- "$*"   # using print instead of unreliable echo³
}

join1 a b c   # => a,b,c
function join2 {
    typeset IFS=$1IFS="$1"
    shift
    print -r -- "$*"
}

join2 + a b c   # => a+b+c

This is almost always what you want. It expands each positional parameter to a separate word, which makes it perfect for taking command line or function arguments in and then passing them on to another command or function. And because it expands using double quotes, it means things don't break if, say, "$1" contains a space or an asterisk (*)³4.

³ echo will or may fail to print its arguments properly if the first starts with - or any contain backslashes, print can be told not to do backslash processing with -r and to guard against argument starting with - or + with the -- (or -) option delimiter. printf '%s\n' "$*" would be the standard alternative but note that ksh88 and pdksh and some of its derivatives still don't have printf builtin.

4 Note that "$@" didn't work properly in the Bourne shell and ksh88 when $IFS didn't contain the space character, as effectively it was implemented as the positional parameter being joined with "unquoted" spaces and the result subject to $IFS splitting. Early versions of the Bourne shell also had that bug that "$@" was expanded to one empty argument when there was no positional parameter, which is one of the reasons why you sometimes see ${1+"$@"} in place of "$@". BothNeither of those bugs don't affect modern Bourne-like shells.

45 The Almquist shell and bosh have local for that instead. bash, yash and zsh also have typeset, aliased to local (also to declare in bash and zsh) with the caveat that in bash, local can only be used in a function.

function join1 {
    typeset IFS=,   # typeset makes a local variable in ksh²
    print -r -- "$*"
}

join1 a b c   # => a,b,c
function join2 {
    typeset IFS=$1
    shift
    print -r -- "$*"
}

join2 + a b c   # => a+b+c

This is almost always what you want. It expands each positional parameter to a separate word, which makes it perfect for taking command line or function arguments in and then passing them on to another command or function. And because it expands using double quotes, it means things don't break if, say, "$1" contains a space or an asterisk (*)³.

³ Note that "$@" didn't work properly in the Bourne shell and ksh88 when $IFS didn't contain the space character, as effectively it was implemented as the positional parameter being joined with "unquoted" spaces and the result subject to $IFS splitting. Early versions of the Bourne shell also had that bug that "$@" was expanded to one empty argument when there was no positional parameter, which is one of the reasons why you sometimes see ${1+"$@"} in place of "$@". Both those bugs don't affect modern Bourne-like shells.

4 The Almquist shell and bosh have local for that instead. bash, yash and zsh also have typeset, aliased to local (also to declare in bash and zsh) with the caveat that in bash, local can only be used in a function.

function join1 {
    typeset IFS=,      # typeset makes a local variable in ksh²
    print -r -- "$*"   # using print instead of unreliable echo³
}

join1 a b c   # => a,b,c
function join2 {
    typeset IFS="$1"
    shift
    print -r -- "$*"
}

join2 + a b c   # => a+b+c

This is almost always what you want. It expands each positional parameter to a separate word, which makes it perfect for taking command line or function arguments in and then passing them on to another command or function. And because it expands using double quotes, it means things don't break if, say, "$1" contains a space or an asterisk (*)4.

³ echo will or may fail to print its arguments properly if the first starts with - or any contain backslashes, print can be told not to do backslash processing with -r and to guard against argument starting with - or + with the -- (or -) option delimiter. printf '%s\n' "$*" would be the standard alternative but note that ksh88 and pdksh and some of its derivatives still don't have printf builtin.

4 Note that "$@" didn't work properly in the Bourne shell and ksh88 when $IFS didn't contain the space character, as effectively it was implemented as the positional parameter being joined with "unquoted" spaces and the result subject to $IFS splitting. Early versions of the Bourne shell also had that bug that "$@" was expanded to one empty argument when there was no positional parameter, which is one of the reasons why you sometimes see ${1+"$@"} in place of "$@". Neither of those bugs affect modern Bourne-like shells.

5 The Almquist shell and bosh have local for that instead. bash, yash and zsh also have typeset, aliased to local (also to declare in bash and zsh) with the caveat that in bash, local can only be used in a function.

added 3 characters in body
Source Link
Stéphane Chazelas
  • 553.6k
  • 92
  • 1.1k
  • 1.6k
function join1 {
    typeset IFS=,   # typeset makes a local variable in ksh²
    print -r -- "$*"
}

join1 a b c   # => a,b,c
function join2 {
    typeset IFS=$1   # typeset makes a local variable in ksh²
    shift
    print -r -- "$*"
}

join2 + a b c   # => a+b+c

¹ though beware in some shells, it doesn't work for multibyte characters.

² typeset which is used to set types and attributes of variables also makes a variable local in ksh4 (in ksh93, that's only for functions defined with the Korn function f {} syntax, not the Bourne f() ... syntax ). It means here IFS will be restored to its previous value when the function returns. This is important, because the commands you run afterward might not work as expected if IFS is set to something non-standard and you forgot to quote some expansions.

² though beware in some shells, it doesn't work for multibyte characters.

function join1 {
    typeset IFS=,
    print -r -- "$*"
}

join1 a b c   # => a,b,c
function join2 {
    typeset IFS=$1   # typeset makes a local variable in ksh²
    shift
    print -r -- "$*"
}

join2 + a b c   # => a+b+c

¹typeset which is used to set types and attributes of variables also makes a variable local in ksh4 (in ksh93, that's only for functions defined with the Korn function f {} syntax, not the Bourne f() ... syntax ). It means here IFS will be restored to its previous value when the function returns. This is important, because the commands you run afterward might not work as expected if IFS is set to something non-standard and you forgot to quote some expansions.

² though beware in some shells, it doesn't work for multibyte characters.

function join1 {
    typeset IFS=,   # typeset makes a local variable in ksh²
    print -r -- "$*"
}

join1 a b c   # => a,b,c
function join2 {
    typeset IFS=$1
    shift
    print -r -- "$*"
}

join2 + a b c   # => a+b+c

¹ though beware in some shells, it doesn't work for multibyte characters.

² typeset which is used to set types and attributes of variables also makes a variable local in ksh4 (in ksh93, that's only for functions defined with the Korn function f {} syntax, not the Bourne f() ... syntax ). It means here IFS will be restored to its previous value when the function returns. This is important, because the commands you run afterward might not work as expected if IFS is set to something non-standard and you forgot to quote some expansions.

added 423 characters in body
Source Link
Stéphane Chazelas
  • 553.6k
  • 92
  • 1.1k
  • 1.6k
function join1() {
    typeset IFS=,
    print -r -- "$*"
}

join1 a b c   # => a,b,c
function join2() {
    typeset IFS=$1   # typeset makes a local variable in ksh (see footnote)ksh²
    shift
    print -r -- "$*"
}

join2 + a b c   # => a+b+c

This is almost always what you want. It expands each positional parameter to a separate word, which makes it perfect for taking command line or function arguments in and then passing them on to another command or function. And because it expands using double quotes, it means things don't break if, say, "$1" contains a space or an asterisk (*)²³.

typeset is how to make a local variable in ksh (bash and ash use local instead). It means IFS will be restored to its previous value when the function returns. This is important, because the commands you run afterward might not work properly if IFS is set to something non-standard.¹typeset which is used to set types and attributes of variables also makes a variable local in ksh4 (in ksh93, that's only for functions defined with the Korn function f {} syntax, not the Bourne f() ... syntax ). It means here IFS will be restored to its previous value when the function returns. This is important, because the commands you run afterward might not work as expected if IFS is set to something non-standard and you forgot to quote some expansions.


 

¹² though beware in some shells, it doesn't work for multibyte characters.

²³ Note that "$@" didn't work properly in the Bourne shell and ksh88 when $IFS didn't contain the space character, as effectively it was implemented as the positional parameter being joined with "unquoted" spaces and the result subject to $IFS splitting. Early versions of the Bourne shell also had that bug that "$@" was expanded to one empty argument when there was no positional parameter, which is one of the reasons why you sometimes see ${1+"$@"} in place of "$@". Both those bugs don't affect modern Bourne-like shells.

4 The Almquist shell and bosh have local for that instead. bash, yash and zsh also have typeset, aliased to local (also to declare in bash and zsh) with the caveat that in bash, local can only be used in a function.

join1() {
    typeset IFS=,
    print -r -- "$*"
}

join1 a b c   # => a,b,c
join2() {
    typeset IFS=$1   # typeset makes a local variable in ksh (see footnote)
    shift
    print -r -- "$*"
}

join2 + a b c   # => a+b+c

This is almost always what you want. It expands each positional parameter to a separate word, which makes it perfect for taking command line or function arguments in and then passing them on to another command or function. And because it expands using double quotes, it means things don't break if, say, "$1" contains a space or an asterisk (*)².

typeset is how to make a local variable in ksh (bash and ash use local instead). It means IFS will be restored to its previous value when the function returns. This is important, because the commands you run afterward might not work properly if IFS is set to something non-standard.


 

¹ though beware in some shells, it doesn't work for multibyte characters.

² Note that "$@" didn't work properly in the Bourne shell and ksh88 when $IFS didn't contain the space character, as effectively it was implemented as the positional parameter being joined with "unquoted" spaces and the result subject to $IFS splitting. Early versions of the Bourne shell also had that bug that "$@" was expanded to one empty argument when there was no positional parameter, which is one of the reasons why you sometimes see ${1+"$@"} in place of "$@". Both those bugs don't affect modern Bourne-like shells.

function join1 {
    typeset IFS=,
    print -r -- "$*"
}

join1 a b c   # => a,b,c
function join2 {
    typeset IFS=$1   # typeset makes a local variable in ksh²
    shift
    print -r -- "$*"
}

join2 + a b c   # => a+b+c

This is almost always what you want. It expands each positional parameter to a separate word, which makes it perfect for taking command line or function arguments in and then passing them on to another command or function. And because it expands using double quotes, it means things don't break if, say, "$1" contains a space or an asterisk (*)³.

¹typeset which is used to set types and attributes of variables also makes a variable local in ksh4 (in ksh93, that's only for functions defined with the Korn function f {} syntax, not the Bourne f() ... syntax ). It means here IFS will be restored to its previous value when the function returns. This is important, because the commands you run afterward might not work as expected if IFS is set to something non-standard and you forgot to quote some expansions.

² though beware in some shells, it doesn't work for multibyte characters.

³ Note that "$@" didn't work properly in the Bourne shell and ksh88 when $IFS didn't contain the space character, as effectively it was implemented as the positional parameter being joined with "unquoted" spaces and the result subject to $IFS splitting. Early versions of the Bourne shell also had that bug that "$@" was expanded to one empty argument when there was no positional parameter, which is one of the reasons why you sometimes see ${1+"$@"} in place of "$@". Both those bugs don't affect modern Bourne-like shells.

4 The Almquist shell and bosh have local for that instead. bash, yash and zsh also have typeset, aliased to local (also to declare in bash and zsh) with the caveat that in bash, local can only be used in a function.

added 736 characters in body
Source Link
Stéphane Chazelas
  • 553.6k
  • 92
  • 1.1k
  • 1.6k
Loading
localize IFS in the first join function
Source Link
glenn jackman
  • 86.8k
  • 16
  • 120
  • 173
Loading
added 75 characters in body
Source Link
Mikel
  • 57.6k
  • 15
  • 134
  • 153
Loading
deleted 12 characters in body; added 8 characters in body
Source Link
Mikel
  • 57.6k
  • 15
  • 134
  • 153
Loading
added 1131 characters in body; deleted 189 characters in body
Source Link
Mikel
  • 57.6k
  • 15
  • 134
  • 153
Loading
added 812 characters in body
Source Link
Mikel
  • 57.6k
  • 15
  • 134
  • 153
Loading
added 193 characters in body
Source Link
Mikel
  • 57.6k
  • 15
  • 134
  • 153
Loading
added 138 characters in body
Source Link
Mikel
  • 57.6k
  • 15
  • 134
  • 153
Loading
added 247 characters in body
Source Link
Mikel
  • 57.6k
  • 15
  • 134
  • 153
Loading
Source Link
Mikel
  • 57.6k
  • 15
  • 134
  • 153
Loading