How to handle variable with special character?

Hi Gurus,

I have a requirement which needs to pass a parameter when calling the script, using this parameter to find a file name stored in master file. then read the file content. the issue is in the file name has a special character "$". don't know how to handle this. below is example:
the master file is:

abc, v$xyz
bcd, x$efg

my script like:

#!/bin/ksh


genfile=$1


while IFS=','  filedir, name
do
cd $filedir
if [ -f ${genfile}* ]; then
cat $name ... "read the file and do something. 
fi
done < Masterfile

the real file name like v$xyz_xxxx_xxxx.xxx

I call the script: ksh scriptname 'v$xyz'.

without "$", the script. with "$", I can put single quote when call the script, but in the script, I don't know how to add single quote in variable "name". please share you idea with me how to handle this.

I know I need to wrap the code with code tag, for some reason, the code tag doesn't work for me.

thanks in advance.

What is your browser? If the button doesn't work, you can always do it by yourself,

```text
stuff
```

What is the script supposed to do with $xyz, etc? Anything? variable xyz doesn't appear in your script.

Your loop is slightly wrong:

while IFS=", " read filedir name
do
        echo "filedir [$filedir] name [$name]"
done < masterfile

thanks Corona688.
the variable is "v$xyz", the file name like v$xyz_xxxx_xxxx.txt.
basically, I want to use variable "v$xyz" to find "v$xyz_xxxx_xxxx.txt" in the directory, if the file exist, then copy file to ABCD_v$xyz.txt. the directory name saved in master file with .

 abc, v$xyz
bcd, x$efg  

'name' is the variable, 'v$xyz' is the value it holds.

The $ is not a problem at all then, the shell won't do anything weird with it. Your [ -f ... ] is problematic though, since * returns more than one file sometimes, which would be a syntax error. So, how about this?

#!/bin/ksh

genfile="$1"

while IFS=", " read filedir name
do
        echo "filedir [$filedir] name [$name]"
        set -- "${name}"* # Overwrites $1, $2, etc with file1, file2, ...
        if [ -f "$1" ]
        then
                echo "Found file $1"
        fi
done < masterfile

No, it is not. A "variable" is something like "$name" or "${name}", where "name" is a name you choose. "$xyz" might be a variable, but "v$xyz" is a literal "v" followed by the content of a variable with the name "xyz".

OK, but is the "$xyz" in this filename now meant literally or should that signify the variable portion of the filename which you want to transport via the variable? If the first is the case a simple quotation will suffice, because this is what it is for - inside of (single) quotes the "$" loses its special meaning to the shell and reverts back to a normal character:

ls -l v$xyz_xxxx_xxxx.txt

will first replace "$xyz_xxxx_xxxx" with the content of a variable named "xyz_xxxx_xxxx" (which most probably will not exist so that it evaluates to "", the empty string) and therefore search for a file named "v.txt". Whereas:

ls -l 'v$xyz_xxxx_xxxx.txt'

(notice the single quotes) will look for a file named exactly this: "v$xyz_xxxx_xxxx.txt".

If "$xyz" is a variable and you want to use that as the changing part of an otherwise fixed filename then this code snippet is for you:

xyz="some$thing"
ls -l "v${xyz}_xxxx_xxxx.txt"

This will search for a file name "vsome$thing_xxxx_xxxx.txt". Because of the braces around "xyz" the shell knows that only this (and not the rest of the string) is the name of the variable. Notice the double quotes: you should habitually double-quote every use of any variable - ever and always! (There are only very few exceptions to this rule of thumb.) This way blanks (yes, filename can contain blanks) will not break your script.

I hope this helps.

bakunin

thanks everybody, it works. I am not sure what i did wrong yesterday. below is my dummy code

$1 is 'v$abc', filename is v$abc_xxxxx_20180120.txt, the value in filename is v$abc_xxxxx
#!/bin/ksh
feed=$1
echo $feed
while read filename
do
if [ -f ${filename}* ]; then
mv ${1}* ${1}_newname
fi
done<filename|grep ${1}

Pseudocode which doesn't do what you want really doesn't tell us what you do want. What is $1 here? And what is 'grep $1' for? It's not going to do anything where you've put it.

Also, I noted above that [ -f * ] is a bad idea since it will fail with syntax errors whenever you match more than one file.

Also, you're still not quoting any of your variables and really should be.

thanks Corona688 for the explanation.
my bad, I didn't explain it clearly.
the requests is pass a value (eg: v$abc) when calling the script, get file directory and file name from master file. (below is sample master file), then go to corresponding directory, rename file (may need split the file as well). below pseudocode is testing code to check I can use variable with "$" sign. yes, there may have more than one files matching. could you please advise the best way to handle multiple matches. thanks in advance

 sample master
directory, filename
abc, v$abc_nau
abc, v$eee_bxy
cde, v$abc_nau 
 #!/bin/ksh
while read filename
do
if [ -f ${filename}* ]; then
mv ${1}* ${1}_newname
fi
done<masterfile|grep ${1}

command to call the script:

 ksh scriptname 'v$abc' 

OK.

May? What decides that?

That is gibberish.

I already showed you one way, if you don't like it, perhaps you need to tell me what you're expecting to happen.

And your code still has that grep on the end which will do exactly nothing where you've put it and I don't know what you're expecting it to do if you put it anywhere else. What is it for?

command to call the script:

 ksh scriptname 'v$abc' 

OK, questions remaining:

  • "variable with $" -- We already told you v$abc is not a variable, so what do you mean now?
  • Splitting the file -- when do you want this to happen, why, how?
  • Multiple matches -- what do you top expect to happen, why, how?
  • What, exactly, are you hoping that grep will do?

I think I finally get it -- that grep is supposed to find the line in the file you want. What for, I'm not certain, as you don't use the file for anything, yet. So I'm also wild-guessing that the 'dir' part of the file ends up being part of the destination file name.

Please try this code and see if it does anything like what you want. It won't actually move any files, just print 'mv inputfile outputfile'.

#!/bin/ksh

# We use a function, so overwriting $1 $2 ... won't affect anything outside
function checkfile {
        dir="$1"
        set -- "${2}"* # Match one or more files, placing in local $1 $2 ...
        if [ ! -f "${1}" ]
        then
                echo "${1} not found" >&2
                return 1
        fi

        echo mv "${1}" "${1}_${dir}"
}

while IFS=", " read dir filename # Split input upon spaces and commas
do
        # Skip lines where filename doesn't match the argument given.
        [ "$1" = "$filename" ] || continue
        # call checkfile.  Inside checkfile, $1=$dir and $2=$filename
        checkfile "$dir" "$filename"
done<masterfile