How to loop names with spaces in bash script? - python-3.x

I'm having a python list output:
names=[Raj Sonakshi, Getendar, Raghu Varan (Mr)]
I run python script using the below bash command
arr=$(python names.py)
Output I got is:
Raj Sonakshi Getendar Raghu Varan (Mr)
When I run for loop each word is printing instead of full name:
for i in $arr;
do
echo $i
done
Output:
Raj
Sonakshi
.....
.....
Expected Output is :
Raj Sonakshi

Put the names in the array in quotes
names=["Raj Sonakshi", "Getendar", "Raghu Varan (Mr)"]

Not sure what your python script's output looks like exactly; the "output" in your question seems to be after bash has turned it into one long string. And you probably don't want it to be a string (as you are doing with arr=$()), but rather you probably want to use a bash array:
declare -a arr
readarray -t arr <<< "$(python names.py)"
for i in "${arr[#]}"; do
echo "$i"
done

Related

Subtracting using Bash

I'm trying to subtract from a decimal number using bash.
For example:
If I have a number 1.0.0.55 I would like to subtract to get to 1.0.0.54.
Here is what I currently have:
#!/bin/bash
LATEST_RELEASE="myproduct_1.0.0.55"
RELEASE_NUMBER=`echo $LATEST_RELEASE | sed 's/[^0-9.]//g'`
echo $RELEASE_NUMBER
#this only works with whole numbers (i.e. 10055)
PREVIOUS_RELEASE=$(($RELEASE_NUMBER - 1))
echo $PREVIOUS_RELEASE
#EOF
Any help would be appreciated!
Thanks!
With bash and its Parameter Expansion:
latest_release="myproduct_1.0.0.55"
first="${latest_release%.*}"
declare -i last # set integer flag
last="${latest_release##*.}"-1
previous_release="$first.$last"
echo "$previous_release"
Output:
myproduct_1.0.0.54
You'll need to isolate the part of that string that you want to extract 1 from since you can't subtrack 1 from a string 1.0.0.55.
Consider using awk here:
echo '1.0.0.55' | awk 'BEGIN{FS=OFS="."}{$4=$4-1}1'
"myproduct_1.0.0.54" isn't a number, so we can't easily subtract 1 from it.
I'd use Parameter-Expansion (${parameter:-word}) to get the part after the last ., and use that at the number so we can + 1.
Then get everything before the last dot to connect the string again:
#!/bin/bash
input="myproduct_1.0.0.55"
minus=$((${input##*.} - 1))
echo "${input%.*}.${minus}"
Will produce:
myproduct_1.0.0.54
Try it online!

Create variable equal to the lines in the file, and assign the variables the value from the file sequentially

I want to create a number of variables equal to the lines in a file and assign to each of those variables a value from the file sequentially.
Say,
file1 contains device1 device2 device3 .....
file2 contains olddevice1 olddevice2 olddevice3 .....
I want values as when I do echo $A = device1
Similarly echo $B = device2 and echo $Z = device26
I tried a for loop, and even an array, but couldn't get through it.
I have tried something like below:
iin=0
var=({A..Z})
for jin in `cat file1`
do
array[$iin]="$var=$jin";
iin=$(($iin+1));
var="$(echo $var | tr '[A-Y]Z' '[B-Z]A')"
printf '%s\n' "${array[#]}"
done`
I believe you're missing the point : variables have fix names in programming languages, like $A, $B, ..., $Z: while programming you need to specify those variables inside your program, you can't expect your program to invent it's own variables.
What you are looking for, are collections, like arrays, lists, ...:
You create a collection A and you can add values to it (A[n]=value_n, or A.SetAt(n, value_n), ..., depending on the kind of collection you're using.
With bash (v4 and later) something like this mapfile code should work:
mapfile -O 1 -t array1 < file1
mapfile -O 1 -t array2 < file2
# output line #2 from both files
echo "${array1[2]}" "${array2[2]}"
# output the last line from both files
echo "${array1[-1]}" "${array2[-1]}"
Notes: mapfile just loads an array, but with a few more options.
-O 1 sets the array subscript to start at 1 rather than the default 0; this isn't necessary, but it makes the code easier to read.

Can't input date variable in bash

I have a directory /user/reports under which many files are there, one of them is :
report.active_user.30092018.77325.csv
I need output as number after date i.e. 77325 from above file name.
I created below command to find a value from file name:
ls /user/reports | awk -F. '/report.active_user.30092018/ {print $(NF-1)}'
Now, I want current date to be passed in above command as variable and get result:
ls /user/reports | awk -F. '/report.active_user.$(date +'%d%m%Y')/ {print $(NF-1)}'
But not getting required output.
Tried bash script:
#!/usr/bin/env bash
_date=`date +%d%m%Y`
active=$(ls /user/reports | awk -F. '/report.active_user.${_date}/ {print $(NF-1)}')
echo $active
But still output is blank.
Please help with proper syntax.
As #cyrus said you must use double quotes in your variable assignment because simple quote are use only for string and not for containing variables.
Bas use case
number=10
string='I m sentence with or wihtout var $number'
echo $string
Correct use case
number=10
string_with_number="I m sentence with var $number"
echo $string_with_number
You can use simple quote but not englobe all the string
number=10
string_with_number='I m sentence with var '$number
echo $string_with_number
Don't parse ls
You don't need awk for this: you can manage with the shell's capabilities
for file in report.active_user."$(date "+%d%m%Y")"*; do
tmp=${file%.*} # remove the extension
number=${tmp##*.} # remove the prefix up to and including the last dot
echo "$number"
done
See https://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion

How to get value from command line using for loop

Following is the code for extracting input from command line into bash script:
input=(*);
for i in {1..5..1}
do
input[i]=$($i);
done;
My question is: how to get $1, $2, $3, $4 values from input command line, where command line code input is:
bash script.sh "abc.txt" "|" "20" "yyyy-MM-dd"
Note: Not using for i in "${#}"
#!/bin/bash
for ((i=$#-1;i>=0;i--)); do
echo "${BASH_ARGV[$i]}"
done
Example: ./script.sh a "foo bar" c
Output:
a
foo bar
c
I don't know what you have against for i in "$#"; do..., but you can certainly do it with shift, for example:
while [ -n "$1" ]; do
printf " '%s'\n" "$1"
shift
done
Output
$ bash script.sh "abc.txt" "|" "20" "yyyy-MM-dd"
'abc.txt'
'|'
'20'
'yyyy-MM-dd'
Personally, I don't see why you exclude for i in "$#"; do ... it is a valid way to iterate though the args that will preserve quoted whitespace. You can also use the array and C-style for loop as indicated in the other answers.
note: if you are going to use your input array, you should use input=("$#") instead of input=($*). Using the latter will not preserve quoted whitespace in your positional parameters. e.g.
input=("$#")
for ((i = 0; i < ${#input[#]}; i++)); do
printf " '%s'\n" "${input[i]}"
done
works fine, but if you use input=($*) with arguments line "a b", it will treat those as two separate arguments.
If I'm correctly understanding what you're trying to do, you can write:
input=("$#")
to copy the positional parameters into an array named input.
If you specifically want only the first five positional parameters, you can write:
input=("${#:1:5}")
Edited to add: Or are you asking, given a variable i that contains the integer 2, how you can get $2? If that's your question, then — you can use indirect expansion, where Bash retrieves the value of a variable, then uses that value as the name of the variable to substitute. Indirect expansion uses the ! character:
i=2
input[i]="${!i}" # same as input[2]="$2"
This is almost always a bad idea, though. You should rethink what you're doing.

Linux SED command in Bash script strips ' from string

I have been putting together a bash script and within it I need to update a file with some neccasary information. The command I am using is below:
sudo sed '
/end/ a\
First line to update\
param 1 'var1'\
param 2 'var2'\
param 3 'var3'\
param 4 'var4'\
end\
' TestFile >TestFileNew
Now this should update the file with the data and should look like this:
end
First line to update
param 1 'var1'
param 2 'var2'
param 3 'var3'
param 4 'var4'
end
The file does get created and the data is in it however it seems to strip the ' symbols from the text and I don't want this to happen, can anyone please help?? An example of what is actually getting produced is below:
end
First line to update
param 1 var1
param 2 var2
param 3 var3
param 4 var4
end
Use "" as the outer quotes:
sudo sed "
/end/ a\\
First line to update\\
param 1 'var1'\\
param 2 'var2'\\
param 3 'var3'\\
param 4 'var4'\\
end\\
" TestFile >TestFileNew
Looks like Igor has already provided an answer that may work for the single quotes.
Regarding the file creation, remember that sudo affects the program (sed) you're running as its option. It does not affect redirection, which is handled by your shell. So if you don't have permission as a user to write TestFileNew, sudo won't help you, the way you're using it above.
You might be better off creating your output somewhere else, then using sudo to move it into place.
sudo sed "/end/ ..." TestFile > /tmp/TestFileNew
sudo mv /tmp/TestFileNew ./TestFileNew
Alternately, this whole script could be run with sudo... I.e. /path/to/myscript is:
#!/bin/bash
sed "/end/ ..." TestFile > TestFileNew
then:
$ sudo /path/to/myscript
Then sudo is running bash instead of sed, and the privileged bash instance is responsible for handling redirection within the script.
In this case, it would probably be simpler to use sed's r command:
$ cat > /tmp/repl << EOF
First line to update
param 1 'var1'
param 2 'var2'
param 3 'var3'
param 4 'var4'
end
EOF
$ sed '/end/r/tmp/repl' TestFile
$ rm /tmp/repl
(I've ignored the sudo/redirect issue, but you probably want to so sudo sh -c 'sed /end/r/tmp/repl/ TestFile > TestFileNew'
Sometimes you have to deal with two types of quotes (html and javascript, for example). Then it is very convenient to put sed commands in a script:
cat >FILE
end
cat >script.sed
/end/ a\
First line to update\
param 1 'var1'\
param 2 'var2'\
param 3 'var3'\
param 4 'var4'\
end
sed -f script.sed FILE
end
First line to update
param 1 'var1'
param 2 'var2'
param 3 'var3'
param 4 'var4'
end

Resources