I've troubles to understand an if syntax of a line in shell:
if [ ! -f *file1.txt* -a ! -f *file2.txt* -a ! -f *file3.txt* ]; then
sbatch file.sh
fi
The * is used because my files are backed up to #file.txt.1# format.
As far as I know, the ! creates a 'if not', the -f 'if the string is a file' but I haven't found any function for the -a flag.
I want to submit the file.sh only if all these files are NOT present.
Does anyone could help?
One easy implementation, compatible with any POSIX shell:
exists_any() {
while [ "$#" -gt 0 ]; do # as long as we have command-line arguments...
[ -e "$1" ] && return 0 # if first argument names a file that exists, success
shift # remove first argument from the list
done
return 1 # nothing matched; report failure
}
if ! exists_any *file1.txt* *file2.txt* *file3.txt*; then
sbatch file.txt
fi
Related
I got some code from here that works pretty well until I get "Argument list too long"
I am NOT a developer and pretty old too :) so if it is not much to ask please explain.
Is there a way the expand DIRCMD like eval does and pass each of the commands one at the time so eval does not break?
for (( ifl=0;ifl<$((NUMFIRSTLEVELDIRS));ifl++ )) { FLDIR="$(get_rand_dirname)"
FLCHILDREN="";
for (( ird=0;ird<$((DIRDEPTH-1));ird++ )) {
DIRCHILDREN=""; MOREDC=0;
for ((idc=0; idc<$((MINDIRCHILDREN+RANDOM%MAXDIRCHILDREN)); idc++)) {
CDIR="$(get_rand_dirname)" ;
# make sure comma is last, so brace expansion works even for 1 element? that can mess with expansion math, though
if [ "$DIRCHILDREN" == "" ]; then
DIRCHILDREN="\"$CDIR\"" ;
else
DIRCHILDREN="$DIRCHILDREN,\"$CDIR\"" ;
MOREDC=1 ;
fi
}
if [ "$MOREDC" == "1" ] ; then
if [ "$FLCHILDREN" == "" ]; then
FLCHILDREN="{$DIRCHILDREN}" ;
else
FLCHILDREN="$FLCHILDREN/{$DIRCHILDREN}" ;
fi
else
if [ "$FLCHILDREN" == "" ]; then
FLCHILDREN="$DIRCHILDREN" ;
else
FLCHILDREN="$FLCHILDREN/$DIRCHILDREN" ;
fi
fi
}
cd $OUTDIR
DIRCMD="mkdir -p $OUTDIR/\"$FLDIR\"/$FLCHILDREN"
eval "$DIRCMD"
echo "$DIRCMD"
}
I tried echo $DIRCMD but do not get the expanded list of commands
'echo mkdir -p /mnt/nvme-test/rndpath/"r8oF"/{"rc","XXKR","p0H"}/{"5Dw0K","oT","rV","coU","uo"}/{"3m5m","uEdA","w4SJp","49"}'
I had trouble following the code, but if I understood it correctly, you dynamically generate a mkdir -p command with a brace expansion:
'mkdir -p /mnt/nvme-test/rndpath/"r8oF"/{"rc","XXKR","p0H"}/{"5Dw0K","oT","rV","coU","uo"}/{"3m5m","uEdA","w4SJp","49"}'
Which then fails when you eval it due to your OS' maximum argument limit.
To get around that, you can instead generate a printf .. command since this is a Bash builtin and not subject to the argument limit, and feed its output to xargs:
dircmd='printf "%s\0" /mnt/nvme-test/rndpath/"r8oF"/{"rc","XXKR","p0H"}/{"5Dw0K","oT","rV","coU","uo"}/{"3m5m","uEdA","w4SJp","49"}'
eval "$dircmd" | xargs -0 mkdir -p
If your xargs doesn't support -0, you can instead use printf "%s\n" and xargs mkdir -p, though it won't behave as well if your generated names contain spaces and such.
If this is for benchmarking, you may additionally be interested to know that you can now use xargs -0 -n 1000 -P 8 mkdir -p to run 8 mkdirs in parallel, each creating 1000 dirs at a time.
I have a bash script that checks if a file already exists or has changed. If either of these case are true, copy the file from one location to anther.
DIR="$( cd "$( dirname "${BASH_SOURCE}" )/my-dir" && pwd )"
FILE="file.json"
copy() {
local SAME=$(cmp --silent "${DIR}/${FILE}" "${PWD}/${FILE}")
if [ ! -f "${PWD}/${FILE}" ] || [ ! $SAME ]; then
cp "${DIR}/${FILE}" "${PWD}/${FILE}" && echo "'$FILE' has been copied." || echo "Copy of '$FILE' has failed.";
else
echo "'$FILE' already exists and has not changed (not copied).";
fi;
}
copy
But when the file exists and has not changed, it is still copied.
echo "$SAME" doesn't echo anything but echo $? echos the exit code 0
So my question is: is it possible to negate the output of the 'cmp' command in a condition?
Thanks.
You need to quote your parameter expansion. If $SAME is the empty string (and it always will be, because you use --silent), your test devolves to [ ! ]. Because ! is a non-empty string, the test succeeds.
if [ ! -f "${PWD}/${FILE}" ] || [ ! "$SAME" ]; then
SAME also needs to contain the output of cmp:
SAME=$(cmp "${DIR}/${FILE}" "${PWD}/${FILE}")
However, it would be better to ignore the actual output of cmp and use its exit status instead.
if [ ! -f "$PWD/$FILE" ] || ! cmp --silent "${DIR}/${FILE}" "${PWD}/${FILE}"; then
Often, I find my self writing the following in BASH script,
if [ -f /very/long/path/tofile/name ]; then
do_someting /very/long/path/tofile/name
fi
For example:
if [ -f /usr/local/bin/virtualenvwrapper.sh ]; then
source /usr/local/bin/virtualenvwrapper.sh
fi
The obvious way to short-cut it would be:
WRAPPER=/usr/local/bin/virtualenvwrapper.sh
if [ -f ${WRAPPER} ]; then
source ${WRAPPER}
fi
But I am wondering if there is some kind of a built-in variable to spare me
the manual declaration?
You can with && operator:
test -f file && cat file
The command after && will run only if first command run successfully.
See: Run command2 only if command1 succeeded in cmd windows shell
If you want to write /very/long/path/tofile/name only once you can define a function and just run it.
function run_smart {
if [ -f "$2" ]; then
"$1" "$2"
fi
}
run_smart cat /very/long/path/tofile/name
I have a little bash script where I compare two files. If one doesn't exist and second one exists, then I will copy/replace backup to main folder.
Somehow this doesn't seem to work. Hope someone can give a hand on this one:
#!/bin/bash
if [ ! -f "/Folder1/$1.jpg" ] && [ -f "/BU_Folder2/$1_BU.jpg" ]; then
cp -fp /BU_Folder2/$1_BU.jpg /Folder1/$1.jpg
cp -fp /BU_Folder2/$1_BU.mp4 /Folder1/$1.mp4
fi
At the prompt, run the following commands:
$ set -- FILENAME # FILENAME is the value you think $1 is supposed to have
$ [ ! -f "/Folder1/$1.jpg" ] && [ -f "/BU_Folder2/$1_BU.jpg" ] && echo success
If the last command does not print "success", then your script probably does not have the value for $1 that you think it does. Add echo $1 to the top of your script to confirm.
If it does print "success", and your script has no error output from cp, I'm not sure what to suggest.
cplane_pid=`pidof hnb_gw.exe`
if [ -z $cplane_pid ]
then
STATUS=`failure`
echo "Cplane hnbgw running $STATUS"
else
STATUS=`success`
echo "Cplane hnbgw running $STATUS"
fi
echo
If there are multiple instances of hnb_gw.exe, pidof will return multiple pids. The -z of [ expects only one pid. One solution might be to use the -s switch of pidof to return only one pid.
You need to Use More Quotes™:
if [ -z "$cplane_pid" ]
Adding set -x before and set +x after the command shows you what it results in. For example:
$ cplane_pid="1 2 3"
$ set -x
$ [ -z $cplane_pid ]
+ '[' -z 1 2 3 ']'
bash: [: too many arguments
In other words, each of the whitespace-separated values in the variable was used as a single parameter. Since -z requires exactly one parameter, this results in a syntax error.
Rather than saving this as a variable, you can simply do
if ! pidof hnb_gw.exe > /dev/null
If the process doesn't exist, it will return 1 ("false").
When you execute
cplane_pid=`pidof hnb_gw.exe`
then cplane_pid can contain more (space separated) items.
So the expansion in
if [ -z $cplane_pid ]
will become
if [ -z firstPid secondPid etc ]
and that is your error "[: too many arguments"
You can solve this with quoting the variable (you should do this ALWAYS in shell)
if [ -z "$cplane_pid" ]
or use [[ (if it's installed on your system), which is better in many ways. For instance you don't need to quote variable :)
if [[ -z $cplane_pid ]]
is the same as
if [[ -z "$cplane_pid" ]]
For testing purposes (and erros like this) use -x hasbang bash option
#!/bin/bash -x
or use debug sections
-- normal code --
set -x # debug section starts here
[ -z $cplane_pid ] && echo zero
eval something
set +x # debug section ends here
-- normal code --
also you can call the script
/bin/bash -x yourScript.sh
pidof can return more than one pid, in these cases, your test will get too many arguments.