[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Help with script.
From: |
Greg Wooledge |
Subject: |
Re: Help with script. |
Date: |
Wed, 19 May 2010 10:29:46 -0400 |
User-agent: |
Mutt/1.4.2.3i |
On Tue, May 18, 2010 at 10:08:54AM -0700, Afflictedd2 wrote:
>
> I'm tryin to build a script that will extract columns from a comma
> sepparated or x delimited file.
And do what with them? That matters, a lot.
> I get the following error:
>
> Naix:Bash Naix$ ./extractCol.sh , cutDemo.input 3
> awk -F',' '{ print $3 }' < cutDemo.input
> awk: '{
> awk: ^ invalid char ''' in expression
That's because you put literal single quotes into the argument you're
giving to awk -F. You don't want to pass literal single quotes along
with the delimiter -- you just want to pass the delimiter itself.
> #!/usr/bin/env bash
>
> DELIMETER="'$1'"
> FILE=$2
> COLUMNS="'{ print \$$3 }'"
>
> echo "awk -F$DELIMETER $COLUMNS < $FILE"
> awk -F$DELIMETER $COLUMNS < $FILE
You have a serious misunderstanding of how shell quoting works. See
<http://mywiki.wooledge.org/Quotes> and
<http://mywiki.wooledge.org/BashFAQ/050>.
You've placed a literal single quote, then the first positional parameter,
then another literal single quote, into the variable DELIMETER (which is
also misspelled). Later you're attempting to use that variable, but you
did not quote it when you used it, and therefore if $1 contains any
whitespace or glob characters, that will break.
Here is how you preserve a variable correctly:
delim="$1"
awk -F"$delim" ...
You are attempting to put part of an awk command into a variable called
COLUMNS. Now, this is a bad idea for two very different reasons:
* The variable COLUMNS already means something else. It's the width
of the terminal. (This is why we don't use all-capital-letter variable
names!)
* As BashFAQ/050 says, putting code into variables is a bad idea. If
you really want a layer of indirection (although I don't see why you'd
want it for something this simple) then you can isolate bits of code in
functions. Don't use variables. Especially if you don't understand
how to quote things properly -- but even if you do, it's quite difficult
to mangle things just right so that it all works after traversing all
the layers.
So, if I understand the question correctly, what you want is:
* Write a program that takes three arguments. The first argument is a
single-character delimiter. The second is a filename. The third is
a field number.
* Extract the <field>th field from every line of <file> (as delimited
by <delimiter>) and write them all to stdout, separated by newlines.
In pure bash:
while IFS="$1" read -r -a array; do
printf "%s\n" "${array[$3 - 1]}"
done < "$2"
In bash+awk:
awk -F"$1" -v field="$3" '{print $field}' "$2"
Yes, that's the entire script. Slap a #!/bin/sh at the top and it's done
(we're not even using bash features in the second one; although we do in
the first one).