for i in {1..$number} acting wierd [duplicate] - shell

This question already has answers here:
Using a variable in brace expansion range fed to a for loop
(5 answers)
Closed 1 year ago.
I have a for loop like this:
for i in {1..$number}
do
echo "Chose a file"
git apply $(zenity --file-selection --file-filter='patch files (patch) | *.patch' --title="Select your patch file")
done
The purpose of the code is for the user to input a file, and it will patch that file. It is supposed to do it multiple times, but it only does it once. I will not post the output, since the error is from the "git apply" and not the for i in {1..$number"}
I can't figure out what is wrong. Can anyone help?

For-in loop with variable is something complex, not intuitive at all:
for i in $( eval echo {0..$number} )
do
echo "Chose a file"
done
source:
https://stackoverflow.com/a/17181832/3957754
If you want something more readable use this:
for (( c=1; c<=$number; c++ ))
do
echo "Welcome $c times"
done
In this you will find more loop samples
https://www.cyberciti.biz/faq/bash-for-loop/

Related

Store each word from a file in an array (in bash) [duplicate]

This question already has answers here:
Creating an array from a text file in Bash
(7 answers)
Closed 2 years ago.
I'm trying to store each word from a file (named f1.txt) in an array (in bash), and then I want to print each element of the array. I tried something like this:
n=0
for varWord in $(cat f1.txt);
do
word[$n]=$varWord
$((n++))
done
for((i=0;i<n;i++));
do
echo $((word[i]))
done
I've also tried this (In fact, it was my first approach, as I would also prefer not to use an additional variable -- varWord, like I did above):
n=0
for word[$n] in $(cat f1.txt);
do
$((n++))
done
for((i=0;i<n;i++));
do
echo $((word[i]))
done
read -r -d '' -a words <inputfile.txt
That's all it needs.

How to make a vim variable determinable by bash? [duplicate]

This question already has answers here:
How to check if a files exists in a specific directory in a bash script?
(3 answers)
Closed 4 years ago.
I'm not sure how to word my question exactly...
I have the code
if grep "mynamefolder" /vol/Homefs/
then
echo "yup"
else
echo "nope"
fi
which gives me the output
grep: /vol/Homefs/: Is a directory
nope
The sh file containing the code and the directory I'm targeting are not in the same directory (if that makes sense).
I want to find the words myfoldername inside /vol/Homefs/ without going through any subdirectories. Doing grep -d skip, which I hoped would "skip" subdirectories and focus only directories, just gives me nope even though the folder/file/word I'm testing it on does exist.
Edit: I forgot to mention that I would also like mynamefolder to be a variable that I can write in putty, something like
./file spaing and spaing being the replacement for myfoldername.
I'm not sure if I did good enough explaining, let me know!
You just want
if [ -e /vol/Homefs/"$1" ]; then
echo yup
else
echo nope
fi
The [ command, with the -e operator, tests if the named file entry exists.
vim is not involved, and grep is not needed.
If you're insisting on using grep, you should know grep doesn't work on directories. You can convert the directory listing to a string.
echo /vol/Homefs/* | grep mynamefolder

How can I build a dynamic parameter list for mailx command in bash linux? [duplicate]

This question already has answers here:
build argument lists containing whitespace
(5 answers)
Closed 6 years ago.
OS: Red Hat Enterprise Linux Server release 5.11 (Tikanga)
I have a code sniplet:
!/usr/bin/env bash
v_mailx_parameter=""
v_cfg_email_adresse_to="john.doe_to#gmail.com"
v_cfg_email_subject="Report from December 2016"
v_tmp_email_text_name="Message Body"
v_email_main_file="appel orange.txt" # -> There is a SPACE in the file name!
v_tmp_path="/home/server/tmp/"
if [ ! -z "${v_email_main_file}" ]
then v_mailx_parameter="${v_mailx_parameter} -a \"${v_tmp_path}${v_email_main_file}\""
/\
||
Here is the problem but I need this because of spaces in the name
fi
echo -e "/bin/mailx ${v_mailx_parameter} -s \"${v_cfg_email_subject}\" \"${v_cfg_email_adresse_to}\""
cat ${v_tmp_email_text_name} | /bin/mailx ${v_mailx_parameter} -s "${v_cfg_email_subject}" "${v_cfg_email_adresse_to}"
exit
PROBLEM:
I want to build up the parameters to the mailx command dynamically.
But I want to use the " double-quotes because there can be spaces in the file names.
Unfortunately the example above does not work... because the mailx takes the double-quotes as if they belong to the file name...and I get an error message.
I do not want to use the if else condition.. because I have many of files I need to send... I need a dynamic solution.
Maybe it is better to understand what my problem is:
It works in such a hardcoded way:
cat ${v_tmp_email_text_name} | /bin/mailx -a "/home/server/tmp/appel orange.txt" -s "${v_cfg_email_subject}" "${v_cfg_email_adresse_to}"
But so NOT:
v_mailx_parameter="-a \"${v_tmp_path}${v_email_main_file}\""
cat ${v_tmp_email_text_name} | /bin/mailx ${v_mailx_parameter} -s "${v_cfg_email_subject}" "${v_cfg_email_adresse_to}"
Thanks!
You need to use an array, which can hold all the arguments to easy logging and invocation. Note, though, that the input redirection to feed the message to mailx is not an argument.
#!/usr/bin/env bash
v_cfg_email_adresse_to="john.doe_to#gmail.com"
v_cfg_email_subject="Report from December 2016"
v_tmp_email_text_name="Message Body"
v_email_main_file="appel orange.txt"
v_tmp_path="/home/server/tmp/"
if [ ! -z "${v_email_main_file}" ]; then
v_mailx_parameters+=( -a "${v_tmp_path}${v_email_main_file}" )
fi
v_mail_x_parameters+=( -s "${v_cfg_email_subject}" )
v_mail_x_parameters+=( "${v_cfg_email_adresse_to}" )
printf '/binmailx %s < %s\n' "${v_mail_x_parameters[*]}" "${v_tmp_email_text_name}"
/bin/mailx "${v_mailx_parameters[#]}" < "${v_tmp_email_text_name}"
One easy way is to use an array.
declare -a parameters=()
parameters+=(-option1 OPTION VALUE)
parameters+=(-option2 "VALUE WITH SPACES")
parameters+=("/path/with spaces")
parameters+=("$PATH_WITH_SPACES")
if
some_condition
then
parameters+=(-optionA)
else
parameters+=(-optionB)
fi
mailx "${parameters[#]}"
The "${parameters[#]}" expansion is special in that it ensure each of the element is separately quoted, without performing word splitting or expansion on the actual value of the elements (like when using "$#").

Getting Bash to parse variables from file input [duplicate]

This question already has answers here:
Forcing bash to expand variables in a string loaded from a file
(13 answers)
Closed 7 years ago.
Let's say I have a file called path.txt containing the text $HOME/filedump/ on a single line. How can I then read the contents of path.txt into a variable, while having Bash parse said content?
Here's an example of what I'm trying to do:
#!/bin/bash
targetfile="path.txt"
target=$( [[ -f $targetfile ]] && echo $( < $targetfile ) || echo "Not set" )
echo $target
Desired output: /home/joe/filedump/
Actual output: $HOME/filedump/
I've tried using cat in place of <, wrapping it in quotes, and more. Nothing seems to get me anywhere.
I'm sure I'm missing something obvious, and there's probably a simple builtin command. All I can find on Google is pages about reading variables from ini/config files or splitting one string into multiple variables.
If you want to evaluate the contents of path.txt and assign that to target, then use:
target=$(eval echo $(<path.txt))
for example:
$ target=$(eval echo $(<path.txt)); echo "$target"
/home/david/filedump/
This might not necessarily suit your needs (depending on the context of the code you provided), but the following worked for me:
targetfile="path.txt"
target=$(cat $targetfile)
echo $target
Here's a safer alternative than eval. In general, you should not be using configuration files that require bash to evaluate their contents; that just opens a security risk in your script. Instead, detect if there is something that requires evaluation, and handle it explicitly. For example,
IFS= read -r path < path.txt
if [[ $path =~ '$HOME' ]]; then
target=$HOME/${path#\$HOME}
# more generally, target=${path/\$HOME/$HOME}, but
# when does $HOME ever appear in the *middle* of a path?
else
target=$path
fi
This requires you to know ahead of time what variables might appear in path.txt, but that's a good thing. You should not be evaluating unknown code.
Note that you can use any placeholder instead of a variable in this case; %h/filedump can be detected and processed just as easily as $HOME/filedump, without the presumption that the contents can or should be evaluated as shell code.

Bash: regarding loops, arrays and variables [duplicate]

This question already has an answer here:
Variables set in a bash 'while read' loop are unset after it [duplicate]
(1 answer)
Closed 8 years ago.
I hope I am asking this in the right place.
I have a fairly simple bash script that I am working on, however I just started scripting bash a few days ago, and I have hit a bit of a stump.
I have seen familiar questions, but before saying read this, or duplicate, or google, understand I have tried many approaches and I am just stuck with this one roadblock.
I have the following code:
find ~/bin/ -type f ! \( -iname '*~' -o -iname '.*' \) -exec basename {} \; | sort | while read line; do
let i=i+1
command_array[$i]="$line"
echo "$i : ${command_array[$i]}"
done
echo $i
echo "array check : ${command_array[*]}"
I would like to get those variables from the loop. As I've read, it seems that somehow I need to make those variables before the pipes ? I am not sure how to accomplish this with my current code. It's a combination of: I am not sure how to restructure the code to find files to accommodate this. It looks like the foolowing is what I should be trying to acheive:
n=0
printf %s "$foo" |
while IFS= read -r line; do
n=$(($n + 1))
done
echo $n
And while I partially understand what's going on here, I am still lost as to how to start to switch what I have to something like this to get variables.
I'm not looking for someone to re-code it for me, but some tips, or hints in getting this going in the right direction would be great.
The typical way to avoid the subshell when using a while read loop to consume command output is to rewrite it to redirect from process substition.
Instead of:
foo | bar | while read baz; do (( i++ )); done
echo "$i" # Unset
use
while read baz; do (( i++ )); done < <(foo | bar)
echo "$i" # Works
PS: ShellCheck automatically warns about this, and links to a page with documentation on how to restructure a while loop like this.

Resources