'*' not working in shellscript

Hi,

To Archive files, I try to move files from one directory to another directory . So i used the below logic,

#!/bin/ksh

 
****Archive*****

mv ${DATA_DIR}/ABC_.dat ${ARCHIVE}

So if i give the complete file name its working fine. But if i use '*', im getting the below error,

mv: cannot stat `PATH`: : No such file or directory

Please help me in this.
Thanks,
Bopty :confused::confused:

Please use CODE tags!

What does the command ****Archive***** do?

How was DATA_DIR set?

How was ARCHIVE set?

Is ABC_.dat a directory in "$DATA_DIR"? By convention, a filename ending in .dat is usually a regular file containing data; not a directory.

Can you post the complete script here?

Hi Don,

Thanks for your Reply.

Instead of # i used * (i.e:###Archive###) here but not in the script.

$DATA_DIR is set to data file path and $ARCHIVE is set to Archive file path. I do echo for the same, its showing the correct path. But the thing is ''. If i use '' for data file its throwing the error.

PFB the script,

#!/bin/ksh
 
export PROGRAM_NAME=`basename $0 .ksh`
 
. ${RMS_RPAS_HOME}/rfx/etc/rmse_rpas_config.env
. ${LIB_DIR}/rmse_rpas_lib.ksh
 
#######
#Archiving
#######
 
mv ${DATA_DIR}/ABC_*.dat ${ARCHIVE}

why cant u use

cd ${DATA_DIR}
mv ABC_*.dat ${ARCHIVE}
cd -

Tried the same, but still it throwing the error :frowning:

mv: cannot stat `ABC_*': No such file or directory

is there such a file named ABC_*?? :smiley: Just wanted to make sure!!

:smiley: its there.

If i use this command (i.e. mv DIR\abc_*) outside the shell script, its working fine. But not inside :wink:

mv DIR\abc_*
is not the same as
mv DIR\ABC_*

Sorry typing error, its (mv DIR\ABC_) only. not abc

OK. I'm totally confused.

You say that:

mv ${DATA_DIR}/ABC_*.dat ${ARCHIVE}

and:

mv ABC_*.dat ${ARCHIVE}

write a diagnostic message saying that mv can't stat ABC_*
and then you say that:

mv DIR\abc_* ${ARCHIVE}

works on the command line, but not in your script.

Do you not see that abc_* is not the same as ABC_*.dat , / is not the same as \ , and you still haven't told us what the value of ${DATA_DIR} is nor what the value of ${ARCHIVE} is?

I can assure you that you won't get a diagnostic about not being able to stat a file named ABC_* from an attempt to move a file named ABC_*.dat .

What operating system are you using? The confusion between / and \ makes me wonder if you're running on Windows instead of on a UNIX or Linux platform.

Pls post output of ls -l ${DATA_DIR}/ABC_*.dat .

Hi Don,

Thanks for you mail.

Your confusion is due to typing issue. Let me clearly explain you.

1.) I try to move files from one directory to another, so used a below command,

mv ${DATA_DIR}\ABC_*.dat ${ARCHIVE}

The Value for DATAA_DIR and ARCHIVE are,

${DATA_DIR} = /u01/data/oracle/rms/UPGRMSBATCH/RETLforRPAS/data
${ARCHIVE} = /u01/data/oracle/rms/UPGRMSBATCH/archive

2.) If i run the above mv command inside my shellscript, im getting the error like

mv: cannot stat `/u01/data/oracle/rms/UPGRMSBATCH/RETLforRPAS/data/ABC_*.dat': No such file or directory

But if i run the same command (i.e:

mv ${DATA_DIR}\ABC_*.dat ${ARCHIVE}

) outside the shell script, then it works fine.

3.) Instead of using '*' if i used the complete file name (i.e: ABC_20120103) its working fine inside the shell script itself. But i don't want to do that, since n number of files with different date format is present in the directory. So i want to move all the files from data directory to archive directory.

I hope now you are clear with my issue.

Thanks,
Bopty

/ABC and \ABC are not same.

echo z\ABC
echo z/ABC

You have not published your script, only some lines

#!/bin/ksh
# if you like to set value for variable, then
DATA_DIR=/u01/data/oracle/rms/UPGRMSBATCH/RETLforRPAS/data
# no spaces after variable name and after = char
ARCHIVE=/u01/data/oracle/rms/UPGRMSBATCH/archive

# will give error if 
# /u01/data/oracle/rms/UPGRMSBATCH/RETLforRPAS/data/ABC_*.dat not include any ABC_*.dat files
mv $DATA_DIR/ABC_*.dat $ARCHIVE
# test your command line
echo mv $DATA_DIR/ABC_*.dat $ARCHIVE
# => you will see the parsed command line => shell try to execute

#     echo /u01/data/oracle/rms/UPGRMSBATCH/RETLforRPAS/data/ABC_*.dat 
# what is the output ?
#     echo $DATA_DIR/ABC_*.dat
# what is the output ?

I think I am clear with your issue. You refuse to see that the backslash character ( \ ) and the slash character ( / ) are different.

You say that the following:

mv ${DATA_DIR}\ABC_*.dat ${ARCHIVE}

works on the command line, but don't understand why the following:

mv ${DATA_DIR}/ABC_*.dat ${ARCHIVE}

doesn't work in your script.

Please execute the following commands exactly and post the results:

uname -a
ls -l /u01/data/oracle/rms/UPGRMSBATCH/RETLforRPAS/data\ABC_*.dat
ls -l /u01/data/oracle/rms/UPGRMSBATCH/RETLforRPAS/dataABC_*.dat
ls -l /u01/data/oracle/rms/UPGRMSBATCH/RETLforRPAS/data/ABC_*.dat

On UNIX and Linux systems, the / character separates components in pathnames. On UNIX and Linux systems, the shell uses \ as an escape character; not to separate a directory name from the name of a file in that directory. Therefore, the command:

mv ${DATA_DIR}\ABC_*.dat ${ARCHIVE}

and the command:

mv ${DATA_DIR}/ABC_*.dat ${ARCHIVE}

are VERY different. If the first one is working on the command line and the second one is not working in your script; use the first one in your script.
Note that the first one uses the asterisk ( * ) to expand to a list of files that match the pattern dataABC_*.dat in the directory:

/u01/data/oracle/rms/UPGRMSBATCH/RETLforRPAS

while the second one uses it expand to a list of files that match the pattern ABC_*.dat in the directory:

/u01/data/oracle/rms/UPGRMSBATCH/RETLforRPAS/data

Hi All,

Thanks for you help. Here is the answer,

ls ${DATA_DIR} | grep "ABC" | while read x; do echo $x; mv ${DATA_DIR}/$x ${ARCHIVE}; done

Thanks,
Bopty :slight_smile:

If the above command works, your current working directory has to be $DATA_DIR. In that case, the commands:

printf "%s\n" $PWD/*ABC*;mv *ABC* $ARCHIVE

will do the same thing MUCH more efficiently, but it will print all of the filenames before it moves any of them.

If it is important to list each filename just before it is moved, the MUCH less efficient commands:

for i in *ABC*
do      echo $PWD/$i
        mv $i $ARCHIVE
done

will still be more efficient than the script you're currently using.

And if there is not any, test it or you get some unwanted action. Example:

for i in *ABC*
do     
        [ "$i" = "*ABC*" ] && continue  # there wasn't any *ABC* files 
        echo $i
        mv $i $ARCHIVE
done

If file name generation result is 0 files, then what you are doing ?
You are doing something for filename *ABC*.

touch *ABC*   # change files timestamp if you have *ABC* files
                    # but if not, touch will create filename *ABC*

Good point. From the description of the problem, I was under the impression that there would always be at least one match, but it would be better to verify that there is a match. The test can be inside the loop, or an if could be added before the loop that exits if there is no match. I believe some shells also have a set special built-in utility option that causes patterns that contain wildcard characters to be removed from the list if there are no matching files.

In my script, if there is no match, $PWD/*ABC* will be printed (with the asterisks) and mv will print a file not found diagnostic message and terminate with a non-zero exit status causing the script to return a non-zero exit status.