Bash. Shell variables logic [duplicate] - linux

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 have the following script:
ls -l | while read permissions number user user2 size month day hour filename
do
if [[ "$filename" == *foo* ]]
then
scount=`expr $scount + $size`
fi
done
echo $scount
The script checks the filename and size of the files in my folder, then it checks for files which contain 'foo' word, then it takes it size and adds it.
I have the following problem, if I call the scount variable from inside the loop it displays the numbers, but when it is outside it shows nothing, as if the variable does not exist. Does it have something to do with shell sessions? How can I display the variable outside of the loop?

Your while loop was run in a subshell so its variables are not visible outside. Try this one:
#!/bin/bash
while read current; do
echo "current: $current"
last=$current
done < <(echo -e "foo\nbar\nbaz")
echo "last: $last"

Related

cannot modify variables inside bash script case statement using while [duplicate]

This question already has answers here:
A variable modified inside a while loop is not remembered
(8 answers)
Closed 3 years ago.
I have s simple bash script as follow:
interval=""
cat conf.param|\
while read param
do
item_=$(echo $param|cut -d "=" -f1)
case ${item_} in
interval)
interval=$(echo $param|cut -d "=" -f2)
echo $interval
;;
method)
method=$(echo $param|cut -d "=" -f2)
;;
esac
done
echo "${interval}"
It reads the contents of a file and stores them in different variables. the issue is that the variables are not set properly inside case segment. I put two echos. The first one (inside case) displays the interval value correctly which is '2', but the second one just after the esac statement displays nothing! it shows an empty blank line.
the conf.param is a simple text file. it has more lines I only printed two lines:
interval=2
method="POST"
Your problem is that using a pipe ("cat conf.param | while read param"), you call a second shell which can not export its variables to the calling one. See this example:
interval=""
cat tmp.txt | while read param; do ##### DON'T DO THIS
interval="A$interval"
done
echo "First attempt: $interval"
interval=""
while read param; do
interval="A$interval"
done < tmp.txt ##### BUT DO THIS INSTEAD
echo "Redirection attempt: $interval"
The file tmp.txt contains 4 lines; the output of the script is:
First attempt:
Redirection attempt: AAAA
As you see, the first attempt retains the old value of interval. The second/redirection attempt instead works because no new process is created.

How to echo this entire code to .bashrc without leaving out characters/strings? [duplicate]

This question already has answers here:
How do I properly quote this bash pipeline for watch?
(2 answers)
Closed 3 years ago.
How can I echo this entire piece of code to .bashrc without leaving out a single character?
# automatic logging of terminal input/output
test "$(ps -ocommand= -p $PPID | awk '{print $1}')" == 'script' || (script -f -q /home/user/.logs/terminal/manjaro/$(date +"%Y-%m- %d_%H:%M:%S")_terminal.log)
When I attempt to enter the following into terminal:
echo "the above code" >> ~/.bashrc
I get the following appended to .bashrc which is nothing like "the above code", its short about 45 or so characters.
# automatic logging of terminal input/output
test script == 'script' || (script -f -q /home/user/.logs/terminal/manjaro/2019-05- 08_09:09:19_terminal.log)
As you can see, it's leaving out A LOT of the original code. I understand this has a lot to do with the number of different quotations and placement, but without altering my code much, or at least to the point where it can still function as its intended, how can I go about getting this to echo to the file properly?
Thank you for every nanosecond of your time.
Wrap your echo'd string with single quotes ' instead of double "

Am I using the correct syntax for my shell script? [duplicate]

This question already has answers here:
Why should there be spaces around '[' and ']' in Bash?
(5 answers)
Command not found error in Bash variable assignment
(5 answers)
Closed 4 years ago.
I wrote a shell script that gets a value from a file and based on that value I want to echo a particular message. My console keeps on saying that there is an error on line 7 and 9. Any suggestions on how to fix it will be greatly appreciated.
export JAVA_HOME='/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home'
echo $JAVA_HOME
export CLASSPATH='/Users/edgarjohnson/Desktop/JarFiles/mlDownload.jar:/ddc/config'
echo $CLASSPATH
var=$(cat /ddc/config/LastRefreshDate.dat)
echo $var
if [$var > 0 ];then
echo "Run Get Latest Update Class"
elif [$var = 0]; then
echo "No need to run any updates"
fi
After [ and before ] there must be a space. Otherwise the variable is substituted and the shell will try to execute a program called [Whatever.
[ itself is actually just a binary which is executed with var's content, =, 0 and ] as arguments and its return code is used to determine whether the if or else branch should be taken.
However the operators used are not really the ones you intend to use, e.g. > is interpreted as shell redirect creating a file called 0 (or overwritting it) and is not actually comparing anything, use -gt instead. = checks string equality, -eq checks value equality.
As mentioned in the comments it may be better to use [[ ]] instead of [ ].

Shell Script working with multiple files [duplicate]

This question already has answers here:
How to iterate over arguments in a Bash script
(9 answers)
Closed 5 years ago.
I have this code below:
#!/bin/bash
filename=$1
file_extension=$( echo $1 | cut -d. -f2 )
directory=${filename%.*}
if [[ -z $filename ]]; then
echo "You forgot to include the file name, like this:"
echo "./convert-pdf.sh my_document.pdf"
else
if [[ $file_extension = 'pdf' ]]; then
[[ ! -d $directory ]] && mkdir $directory
convert $filename -density 300 $directory/page_%04d.jpg
else
echo "ERROR! You must use ONLY PDF files!"
fi
fi
And it is working perfectly well!
I would like to create a script which I can do something like this: ./script.sh *.pdf
How can I do it? Using asterisk.
Thank you for your time!
Firstly realize that the shell will expand *.pdf to a list of arguments. This means that your shell script will never ever see the *. Instead it will get a list of arguments.
You can use a construction like the following:
#!/bin/bash
function convert() {
local filename=$1
# do your thing here
}
if (( $# < 1 )); then
# give your error message about missing arguments
fi
while (( $# > 0 )); do
convert "$1"
shift
done
What this does is first wrap your functionality in a function called convert. Then for the main code it first checks the number of arguments passed to the script, if this is less than 1 (i.e. none) you give the error that a filename should be passed. Then you go into a while loop which is executed as long as there are arguments remaining. The first argument you pass to the convert function which does what your script already does. Then the shift operation is performed, what this does is it throws away the first argument and then shifts all the remaining arguments "left" by one place, that is what was $2 now is $1, what was $3 now is $2, etc. By doing this in the while loop until the argument list is empty you go through all the arguments.
By the way, your initial assignments have a few issues:
you can't assume that the filename has an extension, your code could match a dot in some directory path instead.
your directory assignment seems to be splitting on . instead of /
your directory assignment will contain the filename if no absolute or relative path was given, i.e. only a bare filename
...
I think you should spend a bit more time on robustness
Wrap your code in a loop. That is, instead of:
filename=$1
: code goes here
use:
for filename in "$#"; do
: put your code here
done

"test: too many arguments" message because of special character * while using test command on bash to compare two strings [duplicate]

This question already has answers here:
Meaning of "[: too many arguments" error from if [] (square brackets)
(6 answers)
Closed 5 years ago.
I'm new to shell scripting and I'm having some trouble while using the "test" command and the special character * to compare two strings.
I have to write a shell script which, for every element(both files and directories) contained in the directory passed as the first argument, has to write something(for the solving of my problem it is not relevant to know what has to be written down) on the file "summary.out". What's more, there's a string passed as the second argument. Those files/directories beginning with this string must be ignored(nothing has to be written on summary.out).
Here is the code:
#!/bin/bash
TEMP=NULL
cd "$1"
for i in *
do
if test "$i" != "$2"*;then #Here is where the error comes from
if test -f "$i";then
TEMP="$i - `head -c 10 "$i"`"
elif test -d "$i";then
TEMP="$i - `ls -1 "$i" | wc -l`"
fi
echo $TEMP >> summary.out
fi
done
The error comes from the test which checks whether the current file/directory begins with the string passed as second argument, and it takes place every iteration of the for cycle. It states:"test: too many arguments"
Now, I have performed some tests which showed that the problem has nothing to do with blank spaces inside the $i or $1. The problem is linked to the fact that I use the special character * in the test(if I remove it, everything works fine).
Why can't "test" handle * ? What can I do to fix that?
* gets expanded by the shell.
In bash, you can use [[ ... ]] for conditions instead of test. They support patterns on the right hand side - * is not expanded, as double square brackets are a keyword with higher precedence.
if [[ a == * ]] ; then
echo Matches
else
echo Doesn\'t match
fi

Resources