How to make separate strings of a variant in shell script - linux

#! /bin/sh
VAR=(fdf fef fef)
for i in ${VAR}; do
echo i;
done
Code above has errors. I want to make shell take VAR as a separate string array, and get the output like this:
fdf
fef
fef
how to make it happen ? Thanks !

Try this:
VAR=(aa bb cc)
for i in "${VAR[#]}"
do
echo $i;
done
More info in this article.

The proposed solution only works when using bash. He must also have changed or removed the shebang, otherwise you'll get: syntax error: unexpected "(".
See also his follow up question: How come using ./shell.sh get error but . shell.sh works

Related

How to put array in command-string so that I can eval it?

I've been struggling with this problem for a while. Let's assume I have two scripts.
test1.sh
test2.sh
The code in test1.sh is the following:
array1="/dir/file1.txt /dir/file2.txt /dir/file3.txt"
array2="/dir/file4.txt /dir/file5.txt /dir/file6.txt"
./test2.sh "$array1" "$array2"
The code in test2.sh is the following:
echo $1
echo $2
This works fine, and prints the two arrays correctly:
/dir/file1.txt /dir/file2.txt /dir/file3.txt
/dir/file4.txt /dir/file5.txt /dir/file6.txt
For the project I am working on I have to put the execution code in a variable so that I can run it with the eval-command. I've tried it as follows:
array1="/dir/file1.txt /dir/file2.txt /dir/file3.txt"
array2="/dir/file4.txt /dir/file5.txt /dir/file6.txt"
com="./test2.sh "$array1" "$array2" "
eval $com
However, this returns:
/dir/file1.txt
/dir/file2.txt
How do I get it to give the same input? I've been struggling with this for a while now and Im honestly pretty stuck. I believe it is caused by the many quatation marks in com-variable, but I am not sure.
Many thanks,
Patrick
Make com an array, and you don't need eval.
#!/usr/bin/env bash
# ^^^^- NOT /bin/sh. Run with "bash yourscript", not "sh yourscript"
# none of these are actually arrays; they're just misleadingly-named strings
array1="/dir/file1.txt /dir/file2.txt /dir/file3.txt"
array2="/dir/file4.txt /dir/file5.txt /dir/file6.txt"
# This is an actual array.
com=( ./test2.sh "$array1" "$array2" )
# Expand each element of the array into a separate word of a simple command
"${com[#]}"

bin/bash nested loop does not work

I currently working as a intern at a hosting firm. They asked me to write a bin/bash script to help automate a process to check the user's domain's and .pointers for them. And validate with a "whois" command if the domains/pointers are on our server's.
I'm new with bin/bash scripting but i was told i should check nested loops out. So to test my script out i made similar paths as they would look like on the server. /usr/local/directadmin/data/users/#USER#/domains.list and users/#USER#/domains/#DOMAIN NAME OF USER#.pointers
#part 1
for i in $(cat /home/MrC/Desktop/Users) #<the list of users i need to check)
do
if [ -f "/usr/local/directadmin/data/users/$i/domainlist.txt" ]
then
echo "/usr/local/directadmin/data/users/$i" >> /home/MrC/Desktop/output.tx$
cat "/usr/local/directadmin/data/users/$i/domainlist.txt" >> /home/carlos/Des$
fi
#part 2
for s in $(cat /home/mrC/Desktop/output.txt)
do
if [ -f "/usr/local/directadmin/data/users/$i/domains/$s.pointers" ]
then
echo "/usr/local/directadmin/data/users/$i" >> /home/MrC/Desktop/pointers.$
cat "usr/local/directadmin/data/users/$i/domains/$s.pointers" >> /home/MrC$
fi
done
done
So part 1 works this is the output.txt below
/usr/local/directadmin/data/users/testuser
lolla.nl
blaat2.nl
blaat3.nl
google2.nl
/usr/local/directadmin/data/users/testusers
blaat.nl
google.com
test.nl
pietje.nl
But i cant seem part two to work (no pointer file). my goal with part two of the script is to read the output (domainname) and put it #/$i/domains/$s.pointers.
I'm new on the forum i hope i asked my question in a proper fashion. if some one could give me hints/tips to which direction i should look that would be highly appreciated.
For
Do
if
then
for
do
COMMAND A
COMMAND B
COMMAND C
done
fi
done
while read -r i; do #stuff; done < /home/MrC/Desktop/Users (adjust IFS or specify the delimiter with the -d option to read).
– David C. Rankin

Bash Nested Substring Removal (Extraction)?

I have something similar in a script I'm writing:
CMD="/path/to/cmd,there.sh"
TMP="${CMD##*/}"
echo "${TMP%%,*}"
Is there a way to nest the substring removals in line 2 & 3, or produce the same result in one-line, in pure bash, without going out to another program? The length of ${CMD} is not static. To be clear, I want the output to be simply "cmd".
I've tried the below, with various forms of brackets and quotations, but get a syntax error. This is something (I think) was allowed but isn't in new versions of Bash.
echo "${${CMD##*/}%%,*}"
Unfortunately, no, it's not possible to combine or nest string operations in bash.
With bash:
[[ $CMD =~ .*/([^,]*) ]] && echo ${BASH_REMATCH[1]}
Shell parameter substitution is primitive in that they don't provide functionalities like nesting. However, nobody prevents you from doing a sed thing here.
cmd="/path/to/cmd,there.sh" # Use lower-case identifiers for user variables
cmd=$(sed -E 's#^.*/([^,]+),.*$#\1#' <<<"$cmd")
The <<< enables the use of herestrings in bash.
I've found that zsh actually supports nested string operations, so I actually switched the interpreter to zsh for my script and the below works fine:
echo "${${CMD##*/}%%,*}"
If you want to write the script "in one line", just use ; or && to indicate the end of a line instead of a line-break:
CMD="/path/to/cmd,there.sh"; TMP="${CMD##*/}"; echo "${TMP%%,*}"
or
CMD="/path/to/cmd,there.sh" && TMP="${CMD##*/}" && echo "${TMP%%,*}"
A more elaborate answer about combining commands can be found below this question.
Disclaimer:
I understand that it is debatable whether or not this is a one-liner. But if you are visiting this question looking for a way to throw this in bash, it may answer your question regardless.

Read filename with * shell bash

I'am new in Linux and I want to write a bash script that can read in a file name of a directory that starts with LED + some numbers.(Ex.: LED5.5.002)
In that directory there is only one file that will starts with LED. The problem is that this file will every time be updated, so the next time it will be for example LED6.5.012 and counting.
I searched and tried a little bit and came to this solution:
export fspec=/home/led/LED*
LedV=`basename $fspec`
echo $LedV
If I give in those commands one by one in my terminal it works fine, LedV= LED5.5.002 but if i run it in a bash scripts it gives the result: LedV = LED*
I search after another solution:
a=/home/led/LED*
LedV=$(basename $a)
echo $LedV
but here again the same, if i give it in one by one it's ok but in a script: LedV = LED*.
It's probably something small but because of my lack of knowledge over Linux I cannot find it. So can someone tell what is wrong?
Thanks! Jan
Shell expansions don't happen on scalar assignments, so in
varname=foo*
the expansion of "$varname" will literally be "foo*". It's more confusing when you consider that echo $varname (or in your case basename $varname; either way without the double quotes) will cause the expansion itself to be treated as a glob, so you may well think the variable contains all those filenames.
Array expansions are another story. You might just want
fspec=( /path/LED* )
echo "${fspec[0]##*/}" # A parameter expansion to strip off the dirname
That will work fine for bash. Since POSIX sh doesn't have arrays like this, I like to give an alternative approach:
for fspec in /path/LED*; do
break
done
echo "${fspec##*/}"
pwd
/usr/local/src
ls -1 /usr/local/src/mysql*
/usr/local/src/mysql-cluster-gpl-7.3.4-linux-glibc2.5-x86_64.tar.gz
/usr/local/src/mysql-dump_test_all_dbs.sql
if you only have 1 file, you will only get 1 result
MyFile=`ls -1 /home/led/LED*`

Bash Shell - The : Command

The colon command is a null command.
The : construct is also useful in the conditional setting of variables. For example,
: ${var:=value}
Without the :, the shell would try to evaluate $var as a command. <=???
I don't quite understand the last sentence in above statement. Can anyone give me some details?
Thank you
Try
var=badcommand
$var
you will get
bash: badcommand: command not found
Try
var=
${var:=badcommand}
and you will get the same.
The shell (e.g. bash) always tries to run the first word on each command line as a command, even after doing variable expansion.
The only exception to this is
var=value
which the shell treats specially.
The trick in the example you provide is that ${var:=value} works anywhere on a command line, e.g.
# set newvar to somevalue if it isn't already set
echo ${newvar:=somevalue}
# show that newvar has been set by the above command
echo $newvar
But we don't really even want to echo the value, so we want something better than
echo ${newvar:=somevalue}.
The : command lets us do the assignment without any other action.
I suppose what the man page writers meant was
: ${var:=value}
Can be used as a short cut instead of say
if [ -z "$var" ]; then
var=value
fi
${var} on its own executes the command stored in $var. Adding substitution parameters does not change this, so you use : to neutralize this.
Try this:
$ help :
:: :
Null command.
No effect; the command does nothing.
Exit Status:
Always succeeds.

Resources