ksh script for existence of file - windows

Always i get "Source file not readable or exists, please check the file " for the below code. I use cygwin in my windows machine to run the script. I am getting the same message even when the file is present in the location. How can i get more details as why the file is not readable.
#!/bin/ksh
#
# Scanning source file for existance and readable
file_loc="abc.xml"
if [ -f "$file_loc" -a -r "$file_loc"]
then
print "Source file read.\n"
else
print "Source file not readable or exists, please check the file $file_loc.\n"
fi

A space before the closing bracket is needed:
if [ -f "$file_loc" -a -r "$file_loc" ]

file_loc="abc.xml" && (< ${file_loc:?})
is an alternative check. An advantage is that it returns different messages for different errors; we let the shell do all the work.
How is this constructed? This single line can trigger at least three different messages:
The ${ varname :? optional message } syntax will check for undefined variables,
which can signal a typo in the variable name.
(< ${file_lo:?} )
-bash: file_lo: parameter null or not set
(< filename ) will just attempt to open and close the file.
$ (< nonesuch ) && echo ok
-bash: nonesuch: No such file or directory
$ (< /etc/shadow ) && echo ok
-bash: /etc/shadow: Permission denied

Related

Exit shell script if file doesn't exist

Ive got a .sql job which creates files depending on certain criteria, it writes these with a prefix of TEMP_ as we then have an adaptor that picks up the files and we dont want them picked up before writing is complete.
I need to put a post job in place which renames these files, i have it set up with a number of other job but they all create the files each time they run. This job only creates the files sometimes it runs, depending on the data in the system.
I need to do a check if the file exists and then exit if no file exists.
Ive found a few examples but they all seem to fail, this is where i have got to which i thought was checking if no file, if no file then exit but it fails and displays:
"syntax error at line 16: `TEMP_SUBCON*.csv' unexpected"
This is what i have currently with line 16 being the first line - Above that is just comments:
if [[ ! -f $OUT_DIR -name TEMP_SUBCON*.csv ]] ; then
exit $?
fi
TEMP_DATA_FILE=$(find $OUT_DIR -name TEMP_SUBCON_QTY_output*.csv)
DATA_FILE=$(basename $TEMP_DATA_FILE | cut -c6-)
echo $TEMP_DATA_FILE
echo $DATA_FILE
## Rename the file name, remove the phrase TEMP_, so that EAI can pick the file ##
mv $TEMP_DATA_FILE $OUT_DIR/$DATA_FILE
Can you help guide what ive done incorrectly?
Thanks
If I understand it right, you want to find the files with TEMP_ prefix in your $OUT_DIR, and then if any rename them without the prefix. Then that should do the trick
for file in $OUT_DIR/TEMP_SUBCON_*.txt; do
if [[ -e $file ]]; then
mv $file $OUT_DIR/${file#*SUBCON_}
fi
done
exit
It will go through the directory finding each TEMP_ file and rename them without it. If there is none, it won't do anything.
That syntax is not valid for the [[ ... ]] test.
Why not use the result of the subsequent find command to check if there were any matching files in the specified directory instead, and quit if no files are returned (in other words, quit if the result variable is empty)?
Example:
TEMP_DATA_FILE=$(find $OUT_DIR -name "TEMP_SUBCON_QTY_output*.csv" )
if [[ -z ${TEMP_DATA_FILE:=""} ]] ; then
exit 1
fi
Note 1: you should quote the pattern argument for the find command as shown.
Note 2: it is useful to use set -u in your ksh scripts to cause ksh to abort if variables are unitialized when used (often the cause of errors) , instead of using a default value. However, if you use use set -u then in any test you should explicitly give your own default value. That is the reason for using ${TEMP_DATA_FILE:=""} instead of ${TEMP_DATA_FILE} - to support the often very useful set -u option. Even when you do not use set -u the ${TEMP_DATA_FILE:=""} inside tests makes it explicit what should happen instead of relying on implicit behaviour.
Note 3: you should use set -x when debugging and study every line of the output, it will show you exactly what commands ran with which arguments and what was the result. This helps you to learn how to code in ksh and similar shells.

Bash Script to copy from external drive to Box folder

Trying to write a bash script to copy a large number of files from an external drive into separate directories based on a subject id.
I've included the script I've written below.
I get the following error:
cat: /Volumes/Seagate: No such file or directory
cat: Backup: No such file or directory
cat: Plus: No such file or directory
cat: Drive/Subject_List.txt: No such file or directory
When I try to copy a single file at a time using the terminal, it copies using the exact command I've put in this script. I'm not sure why it's not recognizing the directory when I try and use it in the script below. Any help is greatly appreciated!
#!/bin/bash
#A bash script to copy the structural and functional files into the HCP_Entropy folder
#subject list
SUBJECT_LIST="/Volumes/Seagate/Backup/Plus/Drive/Subject_List.txt
for j in $(cat ${SUBJECT_LIST}); do
echo ${j}
cp /Volumes/Seagate\ Backup\ Plus\ Drive/HCP_DATA/Structural/{j}/unprocessed/3T/T1w_MPR1/${j}_3T_T1w_MPR1.nii.gz /Users/myname/Box/HCP_Entropy/BEN/${j}/anat
done
the line
$SUBJECT_LIST=/Volumes/Seagate\ Backup\ Plus\ Drive/Subject_List.txt
is bogus.
to assign values to a variable, you must not add the $ specifier.
a token starting with $ will be expanded, so $SUBJECT_LIST=... will first be expanded to =... (since you haven't assigned anything to the SUBJECT_LIST variable yet it is empty).
the proper way would be:
SUBJECT_LIST="/Volumes/Seagate Backup Plus Drive/Subject_List.txt"
(this uses quotes instead of escaping each space, which i find much more readable)
you also need to quote variables in case they contain spaces, else they might be interpreted by the command (cp) as multiple arguments.
for j in $(cat "${SUBJECT_LIST}"); do
# ...
done
and of course, you should check whether the source file actually exists, just like the destination directory.
indir="/Volumes/Seagate Backup Plus Drive"
SUBJECT_LIST="${indir}/Subject_List.txt"
cat "${SUBJECT_LIST}" | while read j; do
infile="${indir}/HCP_DATA/Structural/${j}/unprocessed/3T/T1w_MPR1/${j}_3T_T1w_MPR1.nii.gz"
outdir="/Users/myname/Box/HCP_Entropy/BEN/${j}/anat"
mkdir -p "${outdir}"
if [ -e "${infile}" ]; then
cp -v "${infile}" "${outdir}"
else
echo "missing file ${infile}" 1>&2
fi
done

Bash complaining "no such file or directory" in for loop

I have a list of file in variable list_of_files. So if I run the following commands
for file_path in $list_of_files; do
echo "=${file_path}="
done
It gives me this
=./a.py=
=./b.py=
=./c.py=
which means file_path contains a relative path to file, without any redundant spaces before or after.
But if I use cat instead of echo, it complains "No such file or directory"
for file_path in $list_of_files; do
cat ${file_path}
done
But what's interesting is, if I call cat directly cat ./a.py, it works.
It is not a cat-specific problem. It turns out if I check the file existence using if statement, it tells me those files do not exist.
for file_path in $list_of_files; do
if [ -f "$file_path" ]
then
echo 'OK'
else
echo 'NO'
fi
done
Result:
NO
NO
NO
Tried following approaches, but also failed.
Use full absolute path
Remove ./ from all file paths
The reason turns out to be that $list_of_files is colored. So it contains some special characters for coloring purpose but hidden!
I found that using echo "$list_of_files" | od -An -tcx1 (thanks to #BinaryZebra), which displays all the junks coloring the file names.
By using sed -r "s:\x1B\[[0-9;]*[mK]::g", I ruled out those magic bits!

Get output filename in Bash Script

I would like to get just the filename (with extension) of the output file I pass to my bash script:
a=$1
b=$(basename -- "$a")
echo $b #for debug
if [ "$b" == "test" ]; then
echo $b
fi
If i type in:
./test.sh /home/oscarchase/test.sh > /home/oscarchase/test.txt
I would like to get:
test.txt
in my output file but I get:
test.sh
How can I procede to parse this first argument to get the right name ?
Try this:
#!/bin/bash
output=$(readlink /proc/$$/fd/1)
echo "output is performed to \"$output\""
but please remember that this solution is system-dependent (particularly for Linux). I'm not sure that /proc filesystem has the same structure in e.g. FreeBSD and certainly this script won't work in bash for Windows.
Ahha, FreeBSD obsoleted procfs a while ago and now has a different facility called procstat. You may get an idea on how to extract the information you need from the following screenshot. I guess some awk-ing is required :)
Finding out the name of the file that is opened on file descriptor 1 (standard output) is not something you can do directly in bash; it depends on what operating system you are using. You can use lsof and awk to do this; it doesn't rely on the proc file system, and although the exact call may vary, this command worked for both Linux and Mac OS X, so it is at least somewhat portable.
output=$( lsof -p $$ -a -d 1 -F n | awk '/^n/ {print substr($1, 2)}' )
Some explanation:
-p $$ selects open files for the current process
-d 1 selects only file descriptor 1
-a is use to require both -p and -d apply (the default is to show all files that match either condition
-F n modifies the output so that you get one line per field, prefixed with an identifier character. With this, you'll get two lines: one beginning with p and indicating the process ID, and one beginning with `n indicating the file name of the file.
The awk command simply selects the line starting with n and outputs the first field minus the initial n.

Bash No such file or directory

trying to write a bash where the command to be used is specified in a environmental variable, if it is defined. Doing so as follows:
if [ -z $MY_DIFF ];
then
echo Using standard diff $(which diff), change MY_DIFF env variable to use a different one.
echo $(which diff)
$diffv=$(which diff)
else
$diffv=$MY_DIFF
fi
$diffv c.xml c2.xml
But I'm getting:
./bash.sh: line 10: =/opt/gnu/bin/diff: No such file or directory
./bash.sh: line 13: c.xml: command not found
I'm sure the file exists and I do have permission to execute. Any idea what the problem might be?
Remove the extra $ before diffv assignment. Use:
diffv=$(which diff)
And:
diffv=$MY_DIFF
With $ you get:
<diffv value, empty>=<MY_DIFF value, or which diff>
=/opt/gnu/bin/diff

Resources