shell command to skip file in sequence - shell

I run a C++ code for several data files in sequence using:
for i in $(seq 0 100); do ./f.out c2.$(($i*40+495)).bin `c2.avg.$(($i*40+495)).txt; done`
Now if some input files are missing, say c2.575.bin is missing then the command is not executed for the rest of the files. How could I modify the shell command to skip the input files those are missing and move to the next input file?
Thanks.

in the loop, test if file exists before calling a program operating on that file:
for i in $(seq 0 100); do
INPUT=c2.$(($i*40+495)).bin
test -e $INPUT && ./f.out $INPUT c2.avg.$(($i*40+495)).txt
done
This way the ./f.out ... will be executed only for existing input files.
See man test for details.
BTW, the && notation is a shorthand for if. See help if or man sh.

You can use {0..100} instead of $(seq 0 100) for better readability. You can put the following code in a script and execute the script. e.g., runCode.bash
#!/bin/bash
for i in {0..100}
do
# Assign a variable for the filenames
ifn=c2.$(($i*40+495)).bin
# -s option checks if the file exists and size greater than zero
if [ -s "${ifn}" ]; then
./f.out "${ifn}" c2.avg.$(($i*40+495)).txt
else
echo "${ifn} No such file"
fi
done
Change permission and execute the script.
chmod u+x runCode.bash`
./runCode.bash`

Related

Can anyone help me understand this bash script?

I am trying to do some analysis of SSD firmware and have found a bash script called firmware.sh that seems interesting to me. However, I really don't know what I am looking at here.
If anyone can help me understand what this code might be used for, or what it's doing, I would greatly appreciate it!
Here's the bash:
#!/bin/sh -e
FIRMWARE_DIRS="/lib/firmware /usr/local/lib/firmware"
err() {
echo "$#" >&2
if [ -x /usr/bin/logger ]; then
/usr/bin/logger -t "${0##*/}[$$]" "$#"
fi
}
if [ ! -e /sys$DEVPATH/loading ]; then
err "udev firmware loader misses sysfs directory"
exit 1
fi
for DIR in $FIRMWARE_DIRS; do
[ -e "$DIR/$FIRMWARE" ] || continue
echo 1 > /sys$DEVPATH/loading
cat "$DIR/$FIRMWARE" > /sys$DEVPATH/data
echo 0 > /sys$DEVPATH/loading
exit 0
done
echo -1 > /sys$DEVPATH/loading
err "Cannot find firmware file '$FIRMWARE'"
exit 1
Of particular interest to me is the for loop... I think I understand that the $NAME syntax is used for variables in bash but I don't know what those variables are referencing. Thank you for your consideration!
I'll try to explain this line by line.
FIRMWARE_DIRS="/lib/firmware /usr/local/lib/firmware"
FIRMWARE_DIRS is set up with two directories separated by a space. This is set up for the for loop later on in the script.
...
for DIR in $FIRMWARE_DIRS; do
For each loop, DIR is set to each directory stored in FIRMWARE_DIRS
[ -e "$DIR/$FIRMWARE" ] || continue
[ denotes the start of a test, much like if, and ] marks the end of this test.
-e checks if the argument passed is a file or directory that exists.
|| means or and anything to the right of this will execute if the test to the left fails.
continue stops the current iteration of a loop which starts on the next iteration.
FIRMWARE is presumably an environment variable set up prior to this
script running. You can see its value if it has been set up on login
by executing the command echo $FIRMWARE on the command line.
echo 1 > /sys$DEVPATH/loading
Truncates the file /sys$DEVPATH/loading if it exists, then outputs the number 1 to this file.
cat "$DIR/$FIRMWARE" > /sys$DEVPATH/data
Truncates the file /sys$DEVPATH/data if it exists, then outputs the contents of the file(s) $DIR/$FIRMWARE to /sys$DEVPATH/data. If FIRMWARE contains a wildcard *, it will copy the contents of all the files matched.
echo 0 > /sys$DEVPATH/loading
Truncates the file sys$DEVPATH/loading if it exists, then outputs the number 0 to this file.
exit 0
Exits the script with the return status 0 (means it completed OK). This has the effect of ending the script in the for loop at this point for any iteration which passed the test above (the one checking the file or directory exists).
Overall, it looks like it's checking for the first directory that exists in FIRMWARE_DIRS, copies one or more firmware files from there to another location
(/sys$DEVPATH/data) and exits as soon as it's done that once.

Bash Check if a Script Ran Successfully (Exit Code not Working)

I have the following bash script:
echo one
echo two
cd x
echo three
which fails at the 3rd line as there is no directory named x. However, after running the script, when I do $?, 0 is returned, even though the script has an error. How do I detect whether the script ran successfully or not?
Check the condition of directory existence in the script statements:
[ -d x ] && cd x || { echo "no such directory"; exit 1; }
Or put set -e after shebang line:
#!/bin/bash
set -e
echo one
echo two
cd x
echo three
You should end with an exit statement
echo one
echo two
cd x
exitCode=$?
echo three
exit $exitCode;
Then
./myscript
echo $?
1
I have searched all over with no clear answer to this. Put simply it doesn't appear to be a native feature in bash. So I will give you the hard way.
To make a .sh script with multiple commands and you don't know if any will error but you want to check if at least one has. You would need to put a $? at the end of literally every command and redirect it to a text file. Once it's in the text file you could format it like.
Command1 = 0 Success.
Command2 = 127 Fail.
Or you could just add the numbers to the file run it through some kind of calculator to add everything together and if the output is greater than zero then the command at some point failed. But this won't be overly useful if you want the exact number and there are more than one failure.
UPDATED - This is the best way I could find.
You can put this at the top of your script file to catch any errors and exit if it fails.
set -euo pipefail
Feel free to read the manual pages.

Comparing the file's existence from a file and in current directory using shell script

I have a file files.txt with content:
F1.txt
F2.txt
F3.txt
F4.txt
I need to read the file files.txt line by line, and check if it exists in the current directory, if it does, I need to append the date at the end of each of line of files.txt, so that the output should be
F1.txt16032017
F2.txt16032017
F3.txt16032017
F4.txt16032017
I have used following simple shell script.
#!/bin/bash
DT=`date +%d%m%Y`
while IFS=read -r line
do
if [ -f $line]
then
echo "$line$DT" > files.ok
else
echo "$line" > files.notok
fi
done < files.txt
It executes without any error, but does not provide expected output with date append. Can someone tell me if the file existence test is correct
The problem is with your file write operator > which creates a creates a new file on every successful case, you need to have used the >> operator which appends to the existing file.
A much neater approach to your code would be to do
#!/bin/bash
dateToday="$(date +%d%m%Y)"
while IFS= read -r file; do
[ -f "$file" ] && printf "%s\n" "$file$dateToday" >> files.OK || printf "%s\n" "$file" >> files.NOK
done < files.txt
What updates that I have made to improve the script,
Removed the outdated command substitution syntax using backticks `` and used the $(..) for running them.
Double-quoted the variables, lower-cased the local variables.
Fixed the file write operator from > to >>
Used a single line condition making use of the return code of the test ([]) operator. The command after && runs if the condition [ -f "$file" ] is successful and the command after || runs if the condition fails.

How to break loop in shell script used to truncate table?

I'm writing a script truncating tables. The problem is that the script goes in infinite loop.
./n_input contains environment variables that are used in script.
#!/bin/ksh
INPUT_FILE=./n_input
if [ ! -e $INPUT_FILE ];
then
echo "Error: Input file require"
exit 1
fi
source $INPUT_FILE
while read Table
do
TABLE="$DSTN_DATABASE.dbo.$Table"
echo "Table : $TABLE"
QUERY="truncate table $TABLE"
echo $QUERY > ./tmp_file
sqlcmd -m 1 -U $DSTN_USER -P $DSTN_PASSWORD -D -S $DSTN_SERVER -m1 -i ./tmp_file
RET_VALUE=$?
if [ $RET_VALUE -ne 0 ]
then
echo "Error $TABLE"
fi
done < $TABLE_LIST
exit 0
How do I break the loop? I have tried to remove sqlcmd from script and verified that it was working. It's working as expected. Observed the same behavior with sqlcmd -Q option.
$TABLE_LIST file contains only one table name.
You don't need to write the query into temporary file. Use -q, or -Q options instead:
q="truncate table ${TABLE};"
sqlcmd -m 1 -U "$DSTN_USER" -P "$DSTN_PASSWORD" -S "$DSTN_SERVER" -q "$q"
Note the ; at the end of the query. Probably, that's the reason why the script "stalls". That may look like an infinitely running loop.
Also note the use of double quotes. You should wrap variables in double quotes to prevent reinterpretation of the special characters.
By the way, you can locate the exact command that is causing the issue by adding set -x at the beginning of the script. set -x turns on debugging mode. With debugging mode on, you see the commands being executed.
It's very unlikely that the content of $TABLE_LIST file is causing such behavior, unless the file is enormously big. The loop construct is correct, and the number of iterations should match the number of lines in the file.

shell script working fine on one server but not on another

the following script is working fine on one server but on the other it gives an error
#!/bin/bash
processLine(){
line="$#" # get the complete first line which is the complete script path
name_of_file=$(basename "$line" ".php") # seperate from the path the name of file excluding extension
ps aux | grep -v grep | grep -q "$line" || ( nohup php -f "$line" > /var/log/iphorex/$name_of_file.log & )
}
FILE=""
if [ "$1" == "" ]; then
FILE="/var/www/iphorex/live/infi_script.txt"
else
FILE="$1"
# make sure file exist and readable
if [ ! -f $FILE ]; then
echo "$FILE : does not exists. Script will terminate now."
exit 1
elif [ ! -r $FILE ]; then
echo "$FILE: can not be read. Script will terminate now."
exit 2
fi
fi
# read $FILE using the file descriptors
# $ifs is a shell variable. Varies from version to version. known as internal file seperator.
# Set loop separator to end of line
BACKUPIFS=$IFS
#use a temp. variable such that $ifs can be restored later.
IFS=$(echo -en "\n")
exec 3<&0
exec 0<"$FILE"
while read -r line
do
# use $line variable to process line in processLine() function
processLine $line
done
exec 0<&3
# restore $IFS which was used to determine what the field separators are
IFS=$BAKCUPIFS
exit 0
i am just trying to read a file containing path of various scripts and then checking whether those scripts are already running and if not running them. The file /var/www/iphorex/live/infi_script.txt is definitely present. I get the following error on my amazon server-
[: 24: unexpected operator
infinity.sh: 32: cannot open : No such file
Thanks for your helps in advance.
You should just initialize file with
FILE=${1:-/var/www/iphorex/live/infi_script.txt}
and then skip the existence check. If the file
does not exist or is not readable, the exec 0< will
fail with a reasonable error message (there's no point
in you trying to guess what the error message will be,
just let the shell report the error.)
I think the problem is that the shell on the failing server
does not like "==" in the equality test. (Many implementations
of test only accept one '=', but I thought even older bash
had a builtin that accepted two '==' so I might be way off base.)
I would simply eliminate your lines from FILE="" down to
the end of the existence check and replace them with the
assignment above, letting the shell's standard default
mechanism work for you.
Note that if you do eliminate the existence check, you'll want
to either add
set -e
near the top of the script, or add a check on the exec:
exec 0<"$FILE" || exit 1
so that the script does not continue if the file is not usable.
For bash (and ksh and others), you want [[ "$x" == "$y" ]] with double brackets. That uses the built-in expression handling. A single bracket calls out to the test executable which is probably barfing on the ==.
Also, you can use [[ -z "$x" ]] to test for zero-length strings, instead of comparing to the empty string. See "CONDITIONAL EXPRESSIONS" in your bash manual.

Resources