This bash doesn't parse
if ! [[ mkdir -p "$available"
&& mkdir -p "$enabled"
&& mkdir -p "$logroot"
&& chmod 755 "$available" "$enabled" "$logroot" ]]
then
echo "Could not make $available, $enabled, and $logroot."
exit 1;
fi
What's the correct form?
If you want to execute multiple commands chained with &&, then [[ ... ]] is not appropriate.
It seem this is what you intended:
if ! { mkdir -p "$available" &&
mkdir -p "$enabled" &&
mkdir -p "$logroot" &&
chmod 755 "$available" "$enabled" "$logroot"; }
then
echo "Could not make $available, $enabled, and $logroot."
exit 1
fi
To answer your follow-up question, the equivalent of if(!(a && !b && c)) would be:
if ! (a && ! b && c); then
# ...
fi
That is, ! binds only to the term next to it,
and you need to put a space around !. (Thanks #that-other-guy)
Or even better, you can avoid a (...) subshell by using grouping within { ...; } instead (thanks #charles-duffy):
if ! { a && ! b && c; }; then
# ...
fi
You can use it like this in BASH:
if ! { mkdir -p "$available" &&
mkdir -p "$enabled" &&
mkdir -p "$logroot" &&
chmod 755 "$available" "$enabled" "$logroot"; }
then
echo "Could not make $available, $enabled, and $logroot."
fi
&& allows you to enter next command in newline
Instead of ! [[ ... ]] you should use ! { ... } as [[ ... ]] is used for evaluating conditional expressions.
Related
#!/bin/bash
#Toggle Script
# $dirserver/A -> $dirproject/{trunk|branches}/A
if [[ "$1" == "dw" || -z "$1" ]]; then
echo "[+] Delete old link ( $dirserver/A )... "
rm "$dirserver/A"
if [[ "$(readlink -f $dirserver/A)" == *"branches"* ]]; then
ln -s "$dirproject/trunk/A" "$dirserver/A"
echo "[+] Done. You are now in TRUNK"
else
ln -s "$dirproject/branches/A" "$dirserver/A"
echo "[+] Done. You are now in BRANCH."
fi
fi
Expected functionality: Do toggle between symlinks, BRANCH or TRUNK .
Error: ./toggle.sh dw Always end in BRANCH.
Notes: No. There is no word "branches" when it points to trunk.
Thank you in advance.
You are deleting the old link before checking it. Just do not delete it at all, only overwrite.
if [[ "$1" == "dw" || -z "$1" ]]; then
if [[ "$(readlink -f "$dirserver/A")" == *branches* ]]; then
ln -f -s "$dirproject/trunk/A" "$dirserver/A"
else
ln -f -s "$dirproject/branches/A" "$dirserver/A"
fi
fi
I have a script that will check for multiple conditions in if statement and run a desired command if its true.
if [ ! -f /tmp/a ] && [ ! -f /tmp/b ]; then
touch /tmp/c else
echo "file exists" fi
I would now need to know which out of the multiple condition was true.
Eg: /tmp/a or /tmp/b which ever existed. Is there a way to get that in my else condition?
Since your if is using a compound condition, there is no way for else to figure out which part of the compound condition failed. You could rewrite your code this way:
a_exists=0
b_exists=0
[[ -f /tmp/a ]] && a_exists=1 # flag set to 1 if /tmp/a exists
[[ -f /tmp/b ]] && b_exists=1 # flag set to 1 if /tmp/b exists
if [[ $a_exists == 0 && $b_exists == 0 ]]; then
touch /tmp/c
else
[[ $a_exists == 1 ]] && echo "a exists"
[[ $b_exists == 1 ]] && echo "b exists"
fi
The above code can be written even more concisely with the Bash arithmetic operator (( ... )):
a_exists=0
b_exists=0
[[ -f /tmp/a ]] && a_exists=1 # flag set to 1 if /tmp/a exists
[[ -f /tmp/b ]] && b_exists=1 # flag set to 1 if /tmp/b exists
if !((a_exists + b_exists)); then
touch /tmp/c
else
((a_exists)) && echo "a exists"
((b_exists)) && echo "b exists"
fi
This smells like one day there will be more than two files to check. Use a loop:
i_am_happy=yeah
for f in a b
do
if [[ ! -f /tmp/$f ]]
then
echo "Criminy! No $f in tmp!" # or what else you would like to do.
i_am_happy=nope
fi
done
[[ i_am_happy == nope ]] && touch /tmp/c
I have no bash scripting knowledge unforunately. I need a script that reads a cd copied ONE file from the cd to a destination and renames it. Here is my code
#!/bin/bash
mount /dev/cd0 /mnt/
for file in /mnt/*
do
if($file == SO_CV*)
cp SO_CV* /usr/castle/np_new/CVFULLPC.BIN
else if($file == SO_PC*)
cp SO_PC* /usr/castle/np_new/PCMAP.BIN
else if($file == MS_PC*)
cp MS_PC* /usr/castle/np_new/FULLPC.BIN
else if($file == MS_MC*)
cp MS_MC* /usr/castle/np_new/MBFULLPC.BIN
done
umount /mnt/
Could someone tell me if this is even valid bash scripting, or what mistakes I might have made.
Thanks
Jim
Syntax problems. Try this code:
#!/bin/bash
mount /dev/cd0 /mnt/
for file in /mnt/*; do
if [[ "$file" == SO_CV* ]]; then
cp SO_CV* /usr/castle/np_new/CVFULLPC.BIN
elif [[ "$file" == SO_PC* ]]; then
cp SO_PC* /usr/castle/np_new/PCMAP.BIN
elif [[ "$file" == MS_PC* ]]; then
cp MS_PC* /usr/castle/np_new/FULLPC.BIN
elif [[ "$file" == MS_MC* ]]; then
cp MS_MC* /usr/castle/np_new/MBFULLPC.BIN
fi
done
umount /mnt/
an alternative:
#!/bin/bash
error_in_cp () {
{ printf "An ERROR occured while trying to copy: '\s' to its dest file.\n" "$#"
printf "Maybe there were more than 1 file ? or you didn't have the rights necessary to write the destination?"
printf "Exiting..."
} >&2 #to have it on STDERR
exit 1
}
mount /dev/cd0 /mnt/ &&
for file in /mnt/*; do
case "$file" in
SO_CV*) cp -p SO_CV* /usr/castle/np_new/CVFULLPC.BIN || error_in_cp "$file" ;;
SO_PC*) cp -p SO_PC* /usr/castle/np_new/PCMAP.BIN || error_in_cp "$file" ;;
MS_PC*) cp -p MS_PC* /usr/castle/np_new/FULLPC.BIN || error_in_cp "$file" ;;
MS_MC*) cp -p MS_MC* /usr/castle/np_new/MBFULLPC.BIN || error_in_cp "$file" ;;
*) echo "oops, forgot to handle that case: '$file' . ABORTING. "
exit 1
;;
esac
done # no "&&" here so you always umount /mnt/ even if you aborted the copy or the latest command went wrong
umount /mnt/
note: I changed the "cp" to "cp -p" to prevere rights & times... adjust if needed.
note that "&&" at the end of the line is ok
(no need to :
command && \
something
)
You may need to add { and } around each part if there is more than 1 element (here, "case ... esac" is one element, so it's fine)
for more comfort I like to override mkdir like this:
mkdir() {
if [[ "$#" == *--parents* ]]; then
builtin mkdir "$#"
else
builtin mkdir "$#" --parents
fi
}
Unfortunately there is no builtin of mkdir. How can I do a workaround that does the job?
You can use the command built-in instead:
mkdir() {
if [[ "$#" == *--parents* ]]; then
command mkdir "$#"
else
command mkdir "$#" --parents
fi
}
mkdir_p=`which mkdir`
after that you can call it with:
$mkdir_p args...
or
alias mkdir=¨mkdir -p¨
I just think that it is convenient for me to "cd" to the directory where I store some file, ie.
[admin#local /]$ cd /usr/bin/somefile.pl
which as far as I know that the official "cd" command will not work.
so I wrote something like this:
main () {
if [[ "${1}" =~ "(.+/)*(.*){1}" ]] && [ -f "${1}" ] ; then
`\cd ${1%/*}`
elif [ -f "${1}" ] ; then
exit 0
else ; `\cd ${1}`
fi
}
main ${1}
and I alias this cd.sh to the "cd" command:
alias cd='source /somepath/cd.sh'
and this doesn't work.
I've tried to use eval "\cd xxx" instead of just \cd xxx;
How can I fix my script?
It feels like a bad idea to override cd, so I'll suggest a slightly different command, fcd:
fcd() { cd -- "$(dirname -- "$1")"; }
$ fcd /usr/bin/somefile.pl
$ pwd
/usr/bin
Or using parameter expansion to save a call to dirname:
fcd { cd -- "${1%/*}"; }
cd() {
DN="$(dirname "$1")"
if [[ -d "$1" ]]; then
builtin cd "$1"
elif [[ -d "$DN" ]]; then
builtin cd "$DN"
else
echo "$* or $DN: No such directories"
return 1
fi
return 0
}