Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

I have a dash script, and I need to parse $1, which is a string containing two parts separated by ':', such as foo:123. I would like to to save foo in $X and 123 in $Y.

I thought I could use read:

$ echo "foo:123" | tr ':' ' ' | read X Y

but that does not work (no error given)

$ echo $X

gives empty line as output.

Why does my read construct not work? And how could I achieve my goal (any solution, does not have to use read)

share|improve this question
2  
Parameter expansion works: var="foo:123"; echo "${var#*:}"; echo "${var%:*}" –  jasonwryan Apr 26 at 19:36
    
echo doesn't survive the pipe. You can use Process Substitution to achieve what you want: E.g read -r X Y < <(echo "foo:123" | tr ':' ' '); echo "$X" –  val0x00ff Apr 26 at 19:38
    
@val0x00ff There's no process substitution in dash. –  Gilles Apr 26 at 19:40
    
@val0x00ff - process substitution works in bash, but not in dash. –  Martin Vegter Apr 26 at 19:40
    
Oh my mistake. I didn't check that! Now I learned something! THanks –  val0x00ff Apr 26 at 19:41

2 Answers 2

up vote 4 down vote accepted

In dash, each command in Pipelines run in subshell (zsh and AT&T ksh, the rightmost command in pipelines doesn't), so variables X and Y are no longer existed when your command done.

Simply, you can use Parameter Expansion, try:

$ set -- foo:123
$ X=${1%:*}
$ Y=${1#*:}

The example is used for interactive session.

Inside your script, you don't need set -- foo:123.

share|improve this answer
    
@uonglm - thankss, that works. Why do I need the set -- ? –  Martin Vegter Apr 26 at 19:49
    
@MartinVegter: set used for set or unset shell options and positional parameters. In this example, set -- foo:123 set $1 to foo:123. -- marked end of options, let you work with variables start with a dash -. –  cuonglm Apr 26 at 19:54
2  
They don't have to run in subshells. All but one have to run in subshells. In AT&T ksh or zsh the rightmost one doesn't. In bash and dash they all run in subshells. –  Stéphane Chazelas Apr 26 at 22:20
    
@StéphaneChazelas: Thanks, updated my answer. I can find the documentation for zsh, but ksh can't. Can you show me what part of ksh documentation mention this behaviour? –  cuonglm Apr 27 at 3:54
    
@cuonglm, for ksh, I don't think it's documented in the man page, but it's been the case since the 80s so it's fairly wide-spread knowledge. Note that only applies to the AT&T (original) and zsh implementations of ksh, not the pdksh/mksh... one. –  Stéphane Chazelas Apr 27 at 11:09

You can also use the split+glob operator (leave a variable unquoted) (and which you used for no apparent reason in your question):

IFS=:     # configure the split part to use : as the delimiter
set -f    # disable the glob part
set -- $1 # $1 is split on : and parts are stored in $1, $2...
X=$1 Y=$2

You can also do:

printf '%s\n' "$1" | {
  IFS=: read -r X Y
  printf '%s\n' "$X"
}

In dash like bash (but contrary to AT&T ksh or zsh), all parts of a pipeline run in subshells (they need to run in different processes anyway since they run concurrently). Above, we need the part that uses that $X to be in that subshell that reads the output of printf and sets $X.

Note that those two solutions behave differently if $1 contains a newline character or more than one : character.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.