开发者

How to handle variables that contain ";"?

I have a configuration file that contains lines like "hallo;welt;" and i want to do a grep on this file. Whenever i try something like grep "$1;$2" my.config or echo "$1;$2 of even line="$1;$2" my script fails with something like:

: command not found95: line 155: =hallo...

How can i tell bash to ignore ; while evaluating "..." blocks?

EDIT: an example of my code.

# find entry
$line=$(grep "$1;$2;" $PERMISSIONSFILE)
# splitt line
reads=$(echo $line | cut -d';' -f3)
writes=$(echo $line | cut -d';' -f4)
admins=$(echo $line | cut -d';' -f5)

# do some stuff on the permissions

# replace old line with new line
nline="$1;$2;$reads;$writes;$admins"
sed -i "s/$line/$nline/g" $TEMPPERM

my scr开发者_开发问答ipt should be called like this: sh script "table" "a.b.*.>"

EDIT: another, simpler example

$test=$(grep "$1;$2;" temp.authorization.config)

the temp file:

table;pattern;read;write;stuff

the call sh test.sh table pattern results in: : command not foundtable;pattern;read;write;stuff


Don't use $ on the left side of an assignment in bash -- if you do it'll substitute the current value of the variable rather than assigning to it. That is, use:

test=$(grep "$1;$2;" temp.authorization.config)

instead of:

$test=$(grep "$1;$2;" temp.authorization.config)

Edit: also, variable expansions should be in double-quotes unless there's a good reason otherwise. For example, use:

reads=$(echo "$line" | cut -d';' -f3)

instead of:

reads=$(echo $line | cut -d';' -f3)

This doesn't matter for semicolons, but does matter for spaces, wildcards, and a few other things.


A ; inside quotes has no meaning at all for bash. However, if $1 contains a doublequote itself, then you'll end up with

grep "something";$2"

which'll be parsed by bash as two separate commands:

grep "something"   ;     other"
^---command 1----^    ^----command 2---^

Show please show exactly what your script is doing around the spot the error is occurring, and what data you're feeding into it.


Counter-example:

$ cat file.txt
hello;welt;
hello;world;
hell;welt;  
$ cat xx.sh
grep "$1;$2" file.txt
$ bash -x xx.sh hello welt
+ grep 'hello;welt' file.txt
hello;welt;
$

You have not yet classified your problem accurately.


If you try to assign the result of grep to a variable (like I do) your example breaks.

Please show what you mean. Using the same data file as before and doing an assignment, this is the output I get:

$ cat xx.sh
grep "$1;$2" file.txt
output=$(grep "$1;$2" file.txt)
echo "$output"
$ bash -x xx.sh hello welt
+ grep 'hello;welt' file.txt
hello;welt;
++ grep 'hello;welt' file.txt
+ output='hello;welt;'
+ echo 'hello;welt;'
hello;welt;
$

Seems to work for me. It also demonstrates why the question needs an explicit, complete, executable, minimal example so that we can see what the questioner is doing that is different from what people answering the question think is happening.


I see you've provided some sample code:

# find entry
$line=$(grep "$1;$2;" $PERMISSIONSFILE)
# splitt line
reads=$(echo $line | cut -d';' -f3)
writes=$(echo $line | cut -d';' -f4)
admins=$(echo $line | cut -d';' -f5)

The line $line=$(grep ...) is wrong. You should omit the $ before line. Although it is syntactically correct, it means 'assign to the variable whose name is stored in $line the result of the grep command'. That is unlikely to be what you had in mind. It is, occasionally, useful. However, those occasions are few and far between, and only for people who know what they're doing and who can document accurately what they're doing.

For safety if nothing else, I would also enclose the $line values in double quotes in the echo lines. It may not strictly be necessary, but it is simple protective programming.

The changes lead to:

# find entry
line=$(grep "$1;$2;" $PERMISSIONSFILE)
# split line
reads=$( echo "$line" | cut -d';' -f3)
writes=$(echo "$line" | cut -d';' -f4)
admins=$(echo "$line" | cut -d';' -f5)

The rest of your script was fine.


It seems like you are trying to read a semicolon-delimited file, identify a line starting with 'table;pattern;' where table is a string you specify and pettern is a regular expression grep will understand. Once the line is identified you wish to replaced the 3rd, 4th and 5th fields with different data and write the updated line back to the file.

Does this sound correct?

If so, try this code

#!/bin/bash

in_table="$1"
in_pattern="$2"
file="$3"

while IFS=';' read -r -d$'\n' tuple pattern reads writes admins ; do
    line=$(cut -d: -f1<<<"$tuple")
    table=$(cut -d: -f2<<<"$tuple")

    # do some stuff with the variables
    # e.g., update the values
    reads=1
    writes=2
    admins=12345

    # replace the old line with the new line
    sed -i'' -n $line'{i\
'"$table;$pattern;$reads;$writes;$admins"'
;d;}' "$file"
done < <(grep -n '^'"${in_table}"';'"${in_pattern}"';' "${file}")

I chose to update by line number here to avoid problems of unknown characters in the left hand of the substitution.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜