Register
It is currently Thu Jul 31, 2014 11:45 pm

stdin and spaces, attempting to build array


All times are UTC - 6 hours


Post new topic Reply to topic  [ 9 posts ] 
Author Message
 PostPosted: Wed Mar 10, 2010 8:10 pm   

Joined: Wed Mar 10, 2010 8:05 pm
Posts: 25
if I throw an array at my script via STDIN, it treats all spaces as delimiters and I don't want that.

PROGRAM:
Code:
#!/bin/bash - myprog.sh
while read line; do
  for part in ${line[@]} ; do
        echo $part;
  done;
done


COMMAND:
echo one two "three three" four\ four| ./myprog.sh

ACTUAL OUTPUT:
one
two
three
three
four
four

EXPECTED OUTPUT:
one
two
three three
four four


Top
 Profile  
 PostPosted: Wed Mar 10, 2010 9:56 pm   

Joined: Tue Mar 02, 2010 9:55 pm
Posts: 24
Location: Canada
The simplest way to do this is...instead of piping the values into the script you could redirect a file into the script..

Code:
#!/bin/bash

while read f
do
   echo $f
done



datafile
one
two
"three three"
four\ four

usage:
./myprog.sh<datafile

Probably not what your looking for. The only way I can see a solution with piping is to parsing the the data in the script..


Top
 Profile  
 PostPosted: Wed Mar 10, 2010 10:36 pm   

Joined: Tue Mar 02, 2010 9:55 pm
Posts: 24
Location: Canada
Actually I did a little more digging and found out that the bash shell doesn't even pass " or \ in the input string...I tried investigating what the shell passes and this is what I got...
ch[0]->o, 6f
ch[1]->n, 6e
ch[2]->e, 65
ch[3]-> , 20
ch[4]->t, 74
ch[5]->w, 77
ch[6]->o, 6f
ch[7]-> , 20
ch[8]->t, 74
ch[9]->h, 68
ch[10]->r, 72
ch[11]->e, 65
ch[12]->e, 65
ch[13]-> , 20
ch[14]->t, 74
ch[15]->h, 68
ch[16]->r, 72
ch[17]->e, 65
ch[18]->e, 65
ch[19]-> , 20
ch[20]->f, 66
ch[21]->o, 6f
ch[22]->u, 75
ch[23]->r, 72
ch[24]-> , 20
ch[25]->f, 66
ch[26]->o, 6f
ch[27]->u, 75
ch[28]->r, 72
ch[29]->
, a

Notice no " or \ characters


Top
 Profile  
 PostPosted: Wed Mar 10, 2010 10:42 pm   

Joined: Wed Mar 10, 2010 8:05 pm
Posts: 25
yeah I was guessing it was something out of control of my script. does that mean it's impossible?

I'd rather not read from a file, I want to read from stdin.

what I'm making is basically xargs, except it'll execute a command on each piece of input individually, unlike xargs. and other features.

I suppose I could just hack up the xargs source, but this is way more fun :-)


Top
 Profile  
 PostPosted: Wed Mar 10, 2010 10:45 pm   

Joined: Wed Mar 10, 2010 8:05 pm
Posts: 25
... it can't be impossible. other programs do this...

can anyone thing of another script that handles this properly?


Top
 Profile  
 PostPosted: Wed Mar 10, 2010 11:00 pm   

Joined: Mon Mar 02, 2009 3:03 am
Posts: 534
Code:
#!/bin/bash

printf '%s\n' "$@"
Code:
myLargeScript one two "three three" four\ four
one
two
three three
four four


Top
 Profile  
 PostPosted: Thu Mar 11, 2010 12:13 am   

Joined: Wed Mar 10, 2010 8:05 pm
Posts: 25
acceting as parameters isn't what I was going for. anyway I've determines it's not that big of a deal, it still delimits strings by line endings, so piping `ls` and such works just like it does with xargs.

yargs:
Code:
#!/bin/sh

function printhelp {
  echo "Usage: yargs [options] [command]"
  echo ""
  echo " the string '{}' anywhere in [command] will be replaced by a line of standard input."
  echo " the command will be executed one time for each line supplised in standard input."
  echo " if no '{}' string is supplied, the line from standard input will be placed at the "
  echo " end of the command."
  echo ""
  echo "Options:"
  echo "   -p --pretend   output what WOULD be executed, but don't execute."
  echo "   -f --fork   execute all commands in parellel instead of one-by-one"
  echo "   -h --help   print help"
  echo "   -v --version   print version"
}

function printversion {
  echo "yargs - build and execute command lines from individual standard inputs"
  echo "version 0.1, Copyright (C) 2010 Brandon Captain. released under the terms and conditions of the GPL v2.0"
}

if [ -z "$1" ]; then
  printversion;
  printhelp;
  exit 0
fi

ASK=0;
PARALLEL=0;
START=0;
atcommand=0;

for opt in $@; do
  if [[ "${opt:0:1}" != "-" || "$atcommand" == 1 ]] ; then
    atcommand=1;
    COMMAND[${#COMMAND[*]}]="$opt"
    continue;
  fi
  let START=$START+${#opt}

  if [ "$opt" = "-h" ] || [ "$opt" = "--help" ]; then
    printversion;
    printhelp;
    exit 0
  elif [ "$opt" = "-v" ] || [ "$opt" = "--version" ]; then
    printversion;
    exit 0
  fi

  if [ "$opt" = "-f" ] || [ "$opt" = "--fork" ]; then
    PARALLEL=1;
    continue;
  fi

  if [ "$opt" = "-p" ] || [ "$opt" = "--pretend" ]; then
    ASK=1;
    continue;
  fi

  echo "$opt is not a valid option"
  exit 1
done

BRACKETS_SUPPLIED="false";
for opt in $@; do
  if [ "$opt" = "{}" ]; then
    BRACKETS_SUPPLIED="true";
    break;
  fi
done

while read line; do
  parts[${#parts[*]}]="$line"
done

for part in "${parts[@]}"; do

  if [[ "$BRACKETS_SUPPLIED" == "false" ]] ; then
    ex="${COMMAND[@]} $part"
  else
    unset command_tmp # doesn't work to copy array:  command_tmp="${COMMAND[@]}";
    for pcopy in "${COMMAND[@]}"; do
      command_tmp[${#command_tmp[*]}]="$pcopy"
    done;

    for (( i=0; $i < ${#command_tmp[*]}; i++ )); do
      if [ "${command_tmp[$i]}" == "{}" ]; then
   command_tmp["$i"]="$part";
      fi
    done

    ex="${command_tmp[@]}"
  fi

  if [ "$ASK" == "1" ]; then
    echo $ex
    continue
  fi

  if [ "$PARALLEL" == "1" ]; then
    $ex &
  else
    $ex
  fi
done

exit 0
[code]

here's the script I used to use for this task, which is much less elegant.

toeach:
[code]
#!/bin/bash

com=$1
shift

#another method
#while [[ $# -gt 0 ]]; do
#  $com "$1"; shift;
#done

for A in $*; do $com "$1"; shift; done


Top
 Profile  
 PostPosted: Thu Mar 11, 2010 4:42 am   
Moderator
User avatar

Joined: Thu Oct 11, 2007 7:12 am
Posts: 229
Location: London - UK
I haven't read this thread properly as I don't have time today however changing the bash built in variable $IFS (Internal Field Separator) may be handy, check the man page.


Top
 Profile  
 PostPosted: Thu Mar 11, 2010 9:48 am   

Joined: Tue Mar 02, 2010 9:55 pm
Posts: 24
Location: Canada
I case your wondering how I got the shell input, this the code I used..

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char**argv)
{
   int i = 0;
   char ch[200];

   fgets(ch, 200, stdin);

   for (i = 0; i < strlen(ch); ++i)
   {
      fprintf(stdout, "ch[%d]->%c, %x\n", i, ch[i], ch[i]);
   }
   
   exit(EXIT_SUCCESS);
}


usage:
echo one two "three three" four\ four| ./progname


Top
 Profile  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot] and 8 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
cron


BashScripts | Promote Your Page Too
Powered by phpBB © 2011 phpBB Group
© 2003 - 2011 USA LINUX USERS GROUP