Compiling this bash command - linux

For my openVPN configuration, I'm trying to hit this code but it's not working.
Not a big fan of Bash command so I need to help to get this compiled. Any Ideas? (Currently using Kali linux and every time I hit this code it shows error message bash: syntax error near unexpected token &&)
echo "Enter clientName:" && set CLIENTNAME = $< && printf "\n<ca>\n" >> ./client.conf && cat ./ca.crt >> ./client.conf && printf "</ca>\n" >> ./client.conf && printf "\n<cert>" >> ./client.conf && grep -v '^ ' ./$CLIENTNAME.crt | grep -v 'Certificate' >> ./client.conf && printf "</cert>\n" >> ./client.conf && printf "\n<key>\n" >> ./client.conf && cat ./$CLIENTNAME.key >> ./client.conf && printf "</key>\n" >> ./client.conf

The problem is that this is not Bash code; it is Tcsh code:
$ echo $0
-bash
$ echo "Enter clientName:" && set CLIENTNAME = $< && printf "\n<ca>\n" >> ./client.conf && cat ./ca.crt >> ./client.conf && printf "</ca>\n" >> ./client.conf && printf "\n<cert>" >> ./client.conf && grep -v '^ ' ./$CLIENTNAME.crt | grep -v 'Certificate' >> ./client.conf && printf "</cert>\n" >> ./client.conf && printf "\n<key>\n" >> ./client.conf && cat ./$CLIENTNAME.key >> ./client.conf && printf "</key>\n" >> ./client.conf
-bash: syntax error near unexpected token `&&'
Change shell:
$ tcsh
% echo $0
tcsh
% echo "Enter clientName:" && set CLIENTNAME = $< && printf "\n<ca>\n" >> ./client.conf && cat ./ca.crt >> ./client.conf && printf "</ca>\n" >> ./client.conf && printf "\n<cert>" >> ./client.conf && grep -v '^ ' ./$CLIENTNAME.crt | grep -v 'Certificate' >> ./client.conf && printf "</cert>\n" >> ./client.conf && printf "\n<key>\n" >> ./client.conf && cat ./$CLIENTNAME.key >> ./client.conf && printf "</key>\n" >> ./client.conf
Enter clientName:
foo

The tutorial assumes you are using tcsh, not bash or any other POSIX-compatible shell. That said, you can make it work in bash by replacing
set CLIENTNAME = $<
with
IFS= read -r CLIENTNAME

Related

Chained && and || operators in bash scripting

I want to execute a series of commands in a bash script.
If any fail, the script should echo a line describing which line failed, and then exit the function.
Currently, my script echos the output adequately, but doesn't exit the script (because the echo command returns 0).
I have
COMMAND_A || echo "command A failed" | tee -a $SUMMARY_FILE
COMMAND_B || echo "command B failed" | tee -a $SUMMARY_FILE
COMMAND_C || echo "command C failed" | tee -a $SUMMARY_FILE
but these have no dependence on the previous line - I think enclosing with bash -e would also not help, since then either COMMAND_A failing would exit without the echo, or else the echo would succeed and nothing would exit.
Since the echo will succeed, I can't just add && to each line.
I could perhaps use
{ COMMAND_A && \
{ COMMAND_B && \
{ COMMAND_C || echo "C failed" | tee -a $SUM } \
|| echo "B failed" | tee -a $SUM } \
|| echo "A failed" | tee -a $SUM }
but this seems very clunky.
Is there a better syntax/style/method?
For a concrete example:
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DCMAKE_BUILD_TYPE=Release .. || \
echo "$(date +%d/%m/%y-%H:%M:%S): cmake failed for $1" | tee -a $SUMFILE
make -j16 || \
echo "$(date +%d/%m/%y-%H:%M:%S): make failed for $1" | tee -a $SUMFILE
sudo make install && \
echo "$(date +%d/%m/%y-%H:%M:%S): Installed $1" | tee -a $SUMFILE || \
echo "$(date +%d/%m/%y-%H:%M:%S): make install failed for $1" | tee -a $SUMFILE
Edit
I can perhaps get some improvement with
COMMAND_A || { echo "A failed" && false; } && \
COMMAND_B || { echo "B failed" && false; } && \
COMMAND_C && echo "C succeeded" || { echo "C failed" && false; }
but this will still print that A, B and C failed if A fails (even though the commands are short-circuited, hence the improvement)
Since the series of commands is executed within a function, the return statement can be used.
If this were not the case, exit may be the appropriate choice.
Consequently, I can use the idea in the question's edit to write:
standardInstall() {
# Should be passed the directory (ie application/library) name as
# an argument.
if [ -z "$1" ]; then
echo "No argument was passed to standardInstall()"
echo "Exiting"
exit 2
fi
pushd $1/build/
cmake -DCMAKE_INSTALL_PREFIX=$KF5 -DCMAKE_BUILD_TYPE=Release .. || \
{ echo "$(date +%d/%m/%y-%H:%M:%S): cmake failed for $1" \
| tee -a $SUMFILE && return 1; } && \
make -j16 || \
{ echo "$(date +%d/%m/%y-%H:%M:%S): make failed for $1" \
| tee -a $SUMFILE && return 1; } && \
sudo make install && \
echo "$(date +%d/%m/%y-%H:%M:%S): Installed $1" | tee -a $SUMFILE || \
{ echo "$(date +%d/%m/%y-%H:%M:%S): make install failed for $1" \
| tee -a $SUMFILE && return 1; }
popd
}

Weird issue with "sed" command

On my script, this -for unknown some reason- gives me errors when it reaches sed command:
function nzb() {
( [ -z "$1" ] ) && echo "No argument is given!" && return 1
hash="$(echo -n "$1" | md5sum | cut -d" " -f1)"
mkdir "${hash}" && rar a -m0 -v200M "${hash}"/"${hash}".rar "$1" && rm -rf "$1" &&
par2 c -r10 -l "${hash}"/"${hash}".par2 "${hash}"/* && ~/newsmangler-master/mangler.py
-c ~/.newsmangler.conf "{hash}" && sed -i "1i$1\n${hash}\n" ~/hashs.txt
}
.
ERROR: "{hash}" does not exist or is not a file!
ERROR: no valid arguments provided on command line!
But when I -out of curiosity- removed sed's preceding commands, it worked perfectly like it suppose to:
function nzb() {
( [ -z "$1" ] ) && echo "No argument is given!" && return 1
hash="$(echo -n "$1" | md5sum | cut -d" " -f1)"
sed -i "1i$1\n${hash}\n" ~/hashs.txt
}
.
Any Ideas?
EDIT: it seems the problem is located in this area:
. . . && ~/newsmangler-master/mangler.py -c ~/.newsmangler.conf "{hash}" && . . .
Because even this is working:
function nzb() {
( [ -z "$1" ] ) && echo "No argument is given!" && return 1
hash="$(echo -n "$1" | md5sum | cut -d" " -f1)"
mkdir "${hash}" && rar a -m0 -v200M "${hash}"/"${hash}".rar "$1" && rm -rf "$1" &&
par2 c -r10 -l "${hash}"/"${hash}".par2 "${hash}"/* && sed -i "1i$1\n${hash}\n"
~/hashs.txt
}
Replace "{hash}" with "${hash}"

Where is modification required in this shell script to add the value which is not there in file

I am writing shell script to check "kernel.shmall" value. Purpose of script is if kernel.shmall is less than 4194304 then it should modify the value to 4194304. If kernel.shmall is not there is file /etc/system.conf then it should add the value to file kernel.shmall=4194304
if grep -o "kernel.shmall" /emblocal/sysctl.conf > /dev/null
then
oldvalue=$(grep -v '^#' /emblocal/sysctl.conf|grep kernel.shmall|sed 's/=/ /g'| awk '{ print $2}')
if [ $oldvalue -lt 4194304 ]
then
sed -i "s|\("kernel.shmall" *= *\).*|\14194304|" /emblocal/sysctl.conf
fi
else
echo "kernel.shmall=" >> /emblocal/sysctl.conf
sed -i "s|\("kernel.shmall" *= *\).*|\14194304|" /emblocal/sysctl.conf
fi
script is wokring if value is less than 4194304, but it is not adding "kernel.shmall=4194304" if it is not there. can you help me in this to get it done?
Try this:
#!/bin/sh
oldvalue=$(sed '/^#/d;/kernel\.shmall/!d;s/^[^=]*= *//' /emblocal/sysctl.conf)
if [ "$oldvalue" ]; then
[ $oldvalue -lt 4194304 ] &&
sed -i '/kernel\.shmall/{s/=.*/= 4194304/}' /emblocal/sysctl.conf
else
echo "kernel.shmall = 4194304" >> /emblocal/sysctl.conf
fi
Or more succinctly in AWK:
f=$(mktemp)
awk -vn=kernel.shmall '
function max(a,b) {return a<b?b:a}
{
if ($1 == n) oldval = $3
else print
}
END {print n, "=", max(oldval, 4194304)}
' /emblocal/sysctl.conf > "$f" && cp "$f" /emblocal/sysctl.conf
rm "$f"

Linux Script Nested if-statements giving syntax error

I am trying to nest multiple if-statements as the following:
#!/bin/bash
# start_server.sh
#
# Use this script to start the MarketDataTransmitter.
#
# Usage: ./start_server.sh Starts the MarketDataTransmitter.
reset=$(tput sgr0)
red=$(tput setaf 1)
green=$(tput setaf 2)
yellow=$(tput setaf 3)
cyan=$(tput setaf 6)
echo
directory=$(ls -l)
check_exist=$(awk -v a="$directory" -v b="MarketDataTransmitter" 'BEGIN { print index(a, b) }')
if [ "$check_exist" = "0" ]; then
# MarketDataTransmitter is not present.
echo "${red}[ERROR]${reset} Could not start ${yellow}MarketDataTransmitter${reset}."
echo " ${yellow}MarketDataTransmitter${reset} could not be found."
else
# MarketDataTransmitter is present.
processes=$(ps -ef | grep -i "MarketDataTransmitter" | grep -v "grep" | grep -v "bash" | awk '{ print $8 }')
check_run=$(awk -v a="$processes" -v b="MarketDataTransmitter" 'BEGIN { print index(a, b) }')
if [ "$check_run" = "0" ]; then
# MarketDataTransmitter is not running.
if [ -e "srv.log" ]; then
if [ -s "srv.log" ]; then
if [ -d "logs" ]; then
date_time=$(date '+%Y%m%d_%H_%M_%S')
new_log_name="srv_$date_time.log"
mv srv.log $new_log_name
mv $new_log_name logs
else
mkdir logs
date_time=$(date '+%Y%m%d_%H_%M_%S')
new_log_name="srv_$date_time.log"
mv srv.log $new_log_name
mv $new_log_name logs
fi
else
echo "srv.log is empty and will be removed."
rm -rf srv.log
fi
else
# No srv.log but this is to start MarketDataTransmitter so we can ignore.
fi
./MarketDataTransmitter > srv.log &
echo "${yellow}MarketDataTransmitter${reset} has been started."
else
# MarketDataTransmitter is already running.
echo "${red}[ERROR]${reset} Could not start ${yellow}MarketDataTransmitter${reset}."
echo " ${yellow}MarketDataTransmitter${reset} is already running."
fi
fi
echo
However it is giving me syntax complaints saying:
syntax error near unexpected token `fi'
on the very last 'fi'
Does anyone know why?
Thanks.
[EDIT] Full code has been posted.
You have an else statement and fi statement with nothing between them on lines 44-46 (just a comment between them). In bash, you need to have some statement in the body of that else block, or take the else block out.

Position of a string within a string using Linux shell script?

If I have the text in a shell variable, say $a:
a="The cat sat on the mat"
How can I search for "cat" and return 4 using a Linux shell script, or -1 if not found?
With bash
a="The cat sat on the mat"
b=cat
strindex() {
x="${1%%"$2"*}"
[[ "$x" = "$1" ]] && echo -1 || echo "${#x}"
}
strindex "$a" "$b" # prints 4
strindex "$a" foo # prints -1
strindex "$a" "ca*" # prints -1
You can use grep to get the byte-offset of the matching part of a string:
echo $str | grep -b -o str
As per your example:
[user#host ~]$ echo "The cat sat on the mat" | grep -b -o cat
4:cat
you can pipe that to awk if you just want the first part
echo $str | grep -b -o str | awk 'BEGIN {FS=":"}{print $1}'
I used awk for this
a="The cat sat on the mat"
test="cat"
awk -v a="$a" -v b="$test" 'BEGIN{print index(a,b)}'
echo $a | grep -bo cat | sed 's/:.*$//'
This can be accomplished using ripgrep (aka rg).
❯ a="The cat sat on the mat"
❯ echo $a | rg --no-config --column 'cat'
1:5:The cat sat on the mat
❯ echo $a | rg --no-config --column 'cat' | cut -d: -f2
5
If you wanted to make it a function you can do:
function strindex() {
local str=$1
local substr=$2
echo -n $str | rg --no-config --column $substr | cut -d: -f2
}
...and use it as such: strindex <STRING> <SUBSTRING>
strindex "The cat sat on the mat" "cat"
5
You can install ripgrep on MacOS with: brew install --formula ripgrep.
This is just a version of the glenn jackman's answer with escaping, the complimentary reverse function strrpos and python-style startswith and endswith function based on the same principle.
Edit: updating escaping per #bruno's excellent suggestion.
strpos() {
haystack=$1
needle=$2
x="${haystack%%"$needle"*}"
[[ "$x" = "$haystack" ]] && { echo -1; return 1; } || echo "${#x}"
}
strrpos() {
haystack=$1
needle=$2
x="${haystack%"$needle"*}"
[[ "$x" = "$haystack" ]] && { echo -1; return 1 ;} || echo "${#x}"
}
startswith() {
haystack=$1
needle=$2
x="${haystack#"$needle"}"
[[ "$x" = "$haystack" ]] && return 1 || return 0
}
endswith() {
haystack=$1
needle=$2
x="${haystack%"$needle"}"
[[ "$x" = "$haystack" ]] && return 1 || return 0
}
Most simple is -
expr index "The cat sat on the mat" cat
it will return 5

Resources