How would I let the user set a variable to be used in a line of code? - bash

So I have wanted to know if it was possible for a user to set a variable to be used in a code like:
Word 1="Example 1"
Word 2="example 2"
echo $Word 1 $Word 2
Then it would say
Example 1 example 2
I know that this works
But I want to know if its possible to make it so the user of the script could be asked to input the value of word 1 and word 2 like this
what should word one be: 123
What should word two be : 456
Then it would plant the data in the code and the script would generate and run this command:
echo $Word 1 $Word 2
And it would say
123 456

You're looking for the read built-in command.
Example:
% cat reading.bash
#!/bin/bash
echo -n "what should word one be: "
read one
echo -n "what should word two be: "
read two
echo "${one} ${two}"
Running:
% ./reading.bash
what should word one be: abc
what should word two be: xyz
abc xyz

Related

Create a loop for 3 different variables to output all possible combinations

So lets say i have 3 lines of code
ABC
123
!##
How do i create a for loop to output the number of ways to piece them together?
E.G ABC123!##, ABC!##123, 123ABC!##$
here is my current line of code
#!/bin/bash
alphabet='ABC' numbers='123' special='!##'
for name in $alphabet$numbers$special
do
echo $name
done
echo done
alphabet='ABC' numbers='123' special='!##'
for name1 in $alphabet $numbers $special
#on 1st iteration, name1's value will be ABC, 2nd 123 ...
do
for name2 in $alphabet $numbers $special
do
for name3 in $alphabet $numbers $special
do
#here we ensure that we want strings only as combination of that three strings
if [ $name1 != $name2 -a $name2 != $name3 ]
then
echo $name1$name2$name3
fi
done
done
done
if you want also to print strings, like 123123123 and ABCABCABC, remove if condition
You can also do it without a loop at all using brace expansion (but you lose the ability to exclude, e.g. ABCABCABC). For example:
#!/bin/bash
alpha='ABC'
num='123'
spec='!##'
printf "%s\n" {$alpha,$num,$spec}{$alpha,$num,$spec}{$alpha,$num,$spec}
Example Use/Output
$ bash permute_brace_exp.sh
ABCABCABC
ABCABC123
ABCABC!##
ABC123ABC
ABC123123
ABC123!##
ABC!##ABC
ABC!##123
ABC!##!##
123ABCABC
123ABC123
123ABC!##
123123ABC
123123123
123123!##
123!##ABC
123!##123
123!##!##
!##ABCABC
!##ABC123
!##ABC!##
!##123ABC
!##123123
!##123!##
!##!##ABC
!##!##123
!##!##!##

How to extend string to certain length

Hey basically right now my program gives me this output:
BLABLABLA
TEXTEXOUAIGJIOAJGOAJFKJAFKLAJKLFJKL
TEXT
MORE TEXT OF RANDOM CHARACTER OVER LIMIT
which is a result of for loop. Now here's what i want:
if the string raches over 10 characters, cut the rest and add two dots & colon to the end "..:"
otherwise (if the string has less than 10 characters) fill the gap with spaces so they're alligned
so on the example i provided i'd want something like this as output:
BLABLABLA :
TEXTEXOUA..:
TEXT :
MORE TEXT..:
I also solved the first part of the problem (when its over 10 characters), only the second one gives me trouble.
AMOUNT=definition here, just simplyfying so not including it
for (( i=1; i<="$AMOUNT"; i++ )); do
STRING=definition here, just simplyfying so not including it
DOTS="..:"
STRING_LENGTH=`echo -n "$STRING" | wc -c`
if [ "$STRING_LENGTH" -gt 10 ]
then
#Takes
STRING=`echo -n "${STRING:0:10}"$DOTS`
else
#now i dont know what to do here, how can i take my current $STRING
#and add spaces " " until we reach 10 characters. Any ideas?
fi
Bash provides a simple way to get the length of a string stored in a variable: ${#STRING}
STRING="definition here, just simplyfying so not including it"
if [ ${#STRING} -gt 10 ]; then
STR12="${STRING:0:10}.."
else
STR12="$STRING " # 12 spaces here
STR12="${STR12:0:12}"
fi
echo "$STR12:"
The expected output you posted doesn't match the requirements in the question. I tried to follow the requirements and ignored the sample expected output and the code you posted.
Use printf:
PADDED_STRING=$(printf %-10s $STRING)

Variable assignment when reading from file using cat

I have a txt file that is in the format below:
name1 path/to/some/directory
name2 path/to/some/other/directory
name3 path/to/some/directory
name4 path/to/some/other/directory
...
Here is the code I have written to read this file line by line:
NUM=1
for line in $(cat /path/to/my/file.txt); do
if [ $((NUM%2)) -eq 1 ]
then
name= $line #this line does not work
echo $line #while this line works just fine
else
sudo tar -cf /desired/path/$name.tar $line
fi
NUM=$((NUM+1))
done
This code actually reads file word by word, and it alternates between then and else of if statement. Once it assigns a value it has read to variable name (then part inside if), then it uses that variable in command that is performed in else part of if. (This is how I expect it to work.)
The problem that arises is that variable assignment in then part of if seems not to work, it sees word it has just read as command, and doesn't assign its value to variable. I tried to echo it and it works just fine.
Why name= $line variable assignment is not working?
Thank you for any suggestions, comments or answers.
The assignments in bash require no space around =.
Hence, you need to say:
name="$line"
^ ^
quotes!
This happens because anything happening after the declaration is considered a command. See for example this, that tries to define r to 2 and then echo 1 is executed:
$ r=2 echo 1
1
This is why it is also a good thing to quote the declaration: name="$line".
Regarding the parsing and definition of variables of the file, you can maybe use this approach:
declare $('s/\s\+/="/; s/$/"/' a)
This replaces the spaces in between the first and second word by =" and the end of line with ". This way, name /path/ gets converted into name="/path/". By using declare, this command gets executed and makes variables be ready for use.
$ cat a
name1 aa
name2 rr
name5 hello
$ sed 's/\s\+/="/; s/$/"/' a
name1="aa"
name2="rr"
name5="hello"
$ declare $('s/\s\+/="/; s/$/"/' a)
So now you have the variables ready to use:
$ echo "$name5"
hello
And finally, note that this is equivalent (and better) than for line in $(cat /path/to/my/file.txt):
while IFS= read -r val1 val2 ...
do
... things ...
done < /path/to/my/file.txt

Output a record from an existing file based on a matching condition in bash scripting

I need to be able to output a record if a condition is true.
Suppose this is the existing file,
Record_ID,Name,Last Name,Phone Number
I am trying to output record if the last name matches. I collect user input to get last name and then perform the following operation.
read last_name
cat contact_records.txt | awk -F, '{if($3=='$last_name')print "match"; else print "no match";}'
This script outputs no match for every record within contact_records.txt
Your script has two problems:
First, $last_name is not considered quoted in the context of 'awk'. For example, if "John" is to be queried, you are comparing $3 with the variable John rather than string "John". This can be fixed by adding two double-quotes as below:
read last_name
cat contact_records.txt | awk -F, '{if($3=="'$last_name'")print "match"; else print "no match";}'
Second, it actually scans the whole contact_records.txt and prints match/no match for each line of comparison. For example, contact_records.txt has 100 lines, with "John" in it. Then, querying if John is in it by this script yields 1 "match"'s and 99 "no match"'s. This might not be what you want. Here's a fix:
read last_name
if [ `cat contact_records.txt | cut -d, -f 3 | grep -c "$last_name"` -eq 0 ]; then
echo "no match"
else
echo "match"
fi

Using output of command to generate autocompletion commands for zsh

Hey, I'm trying to get zsh to run a git command, and use the output to generate autocomplete possibilities.
The command I'm trying to run is
git log -n 2 --pretty=format:"'%h %an'"
And here's the code I'm using:
local lines words
lines=(${(f)$(git log -n 2 --pretty=format:"'%h %an'")})
words=${(f)$(_call_program foobar git log -n 2 --pretty=format:"%h")}
echo "Length of lines is " ${#lines[#]} " value is " ${lines}
echo "Length of words is " ${#words[#]} " value is " ${words}
compadd -d lines -a -- words
This doesn't work at all...it thinks that words is a single element and lines aren't getting printed properly at all.
However, when I try to setup an array of strings by hand, it all works.
local lines words
lines=('one two' 'three')
words=('one two' 'three')
echo "Length of lines is " ${#lines[#]} " value is " ${lines}
echo "Length of words is " ${#words[#]} " value is " ${words}
compadd -d lines -a -- words
To force words being an array, you should use either
words=( ${(f)...} )
or
set -A words ${(f)...}
. If you use just words=${(f)...}, you will always get one value. By the way, why have you added parenthesis around ${(f)...} when you were writing lines definition, but have not done it for words?
Also, there is another thing to concern: ${(f)$(...)} should be replaced with ${(f)"$(...)"}. It is some black magic here: I don't know why first one does emit a single scalar value, while second one does emit an array of scalar values, just was pointed to this fact by someone here on stackoverflow.
Thanks for the help, ZyX, here's the final script for anyone who cares
local lines words
lines=(${(f)"$(git log -n 15 --pretty=format:"'%h - %an - %s'")"} )
words=(${(f)"$(git log -n 15 --pretty=format:"%h")"})
compadd -l -d lines -a -- words
I had a more complicated situation. I was trying to grep many files for a string, then edit the resulting list of files. The use of ** and * wildcards didn't let the above solution work for me. I did get it to work by breaking up into 2 steps:
> tmp=$(grep -l someString **/*.clj)
> fileList=( ${(f)tmp} )

Resources