Bash loop with grep containing variable [duplicate] - linux

This question already has an answer here:
Tilde not expanded when quoting on the right hand side of a Bash variable assignment [duplicate]
(1 answer)
Closed 1 year ago.
I have a function which should loop through every customer in an array and execute a grep to that directory.
test(){
set -x;
export customers=( customer1 customer2 customer3 );
export repo_path="~/repodir";
export output_path='/tmp';
for i in "${customers[#]}"
do
echo "${repo_path}/PEC/repo-${i}/build.yml"
grep 'link: ' $repo_path/PEC/repo-$i/build.yml | cut -d '/' -f 2 | sed 's/.git//g'
done | sort -u > ${output_path}/repos.txt
echo "${output_path}/repos.txt";
}
For some reason I get the following error message:
grep: ~/repodir/PEC/customer1/build.yml: No such file or directory
But when I check that exact same path I can see and read the file...
The first echo command also doesn't seem to be executing.
When I replace grep 'link: ' $repo_path/PEC/repo-$i/build.yml with grep 'link: ' ~/repodir/PEC/repo-$i/build.yml it does work.
I have tried various ways to define the variable like ${repo_path}, adding different types of quotes, ... So I basically don't know what I can do to make it work anymore.

$HOME is an environment variable, that is set to contain the home folder of the current user. The terminal session should have access to this environment variable at all times, unless this has been removed.
~ is a shell expansion symbol, one of the symbols that is processed before the actual command is performed. ~ alone expands to the value of $HOME.
Your code,
export repo_path="~/repodir";
the ~ is in a string and may not be processed, if you want to use a ~ try escaping the character. For readability using the $HOME variable would be simpler.

Related

Populating a PATH env variable using programmatic command substitution $() leads to a literal giant string, rather than tokenized paths

I'm creating a PATH environment variable that begins with /foo and ends with /bar; and in between I "sandwich" in a collection of related bin paths that I programmatically concatenate together, as shown:
export PATH=/foo:$(ls -1d /path/to/*/bin | xargs | sed -e 's/ /:/'g):/bar
The issue I'm having is that the in-between collection of paths are interpreted as one giant string, rather than as tokenized paths separated by a colon (":").
I tried variations in a attempt to get a tokenized result, such as:
export PATH=/foo:$(echo $(ls -1d /path/to/*/bin | xargs | sed -e 's/ /:/'g)):/bar
but no luck. I also tried variants that include an eval(1), and so on. I suppose I can next try using find(1) and friends.
What does work is pasting in the literal long string, but that's a bummer because it's not programmatic.
Incidentally, this issue isn't specific to PATH because substituting in export BLAH=... results in the same issue.
Any ideas for modifying the above so that the result is tokenized? You can try this yourself by creating, say, user$ mkdir -p /tmp/{1,2,3,4}/bin and playing around.
Whatever the solution is, it's just not coming to me today. =:)

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 "

"Command not found" piping a variable to cut when output stored in a variable [duplicate]

This question already has answers here:
How to pass the value of a variable to the standard input of a command?
(9 answers)
Closed 5 years ago.
In a bash script I am using a variable to hold a path like this:
MY_DIR=/just/a/string/to/my/path
And I want to remove the last two parts of it so it looks like this:
/just/a/string
I am using 'cut' to do it, like this:
echo $MY_DIR | cut -d'/' -f-4
The output is what I expect. Fine.
But I want to store in an other variable, like this:
MY_DIR2=$($MY_DIR | cut -d'/' -f-4)
When I execute the script I get the error:
... /just/a/string/to/my/path: No such file or directory
Why is the direct output with echo working, but storing the output in a variable is not?
You need to pass an input string to the shell command using a pipeline in which case cut or any standard shell commands, reads from stdin and acts on it. Some of the ways you can do this are use a pipe-line
dir2=$(echo "$MY_DIR" | cut -d'/' -f-4)
(or) use a here-string which is a shell built-in instead of launching a external shell process
dir2=$(cut -d'/' -f-4 <<< "$MY_DIR")
Use the grave accent(`) to emulate a command, and use echo too.
MY_DIR2=`echo $MY_DIR | cut -d'/' -f-4`

Capturing command output in a shell variable isn't working [duplicate]

This question already has answers here:
How do I set a variable to the output of a command in Bash?
(15 answers)
Closed 5 years ago.
I am new to shell scripting, and need to output a series of commands to a local variable in a shell script, but keep on failing. For instance, the output of grep -c to a variable that will be use in an if statement. If anyone can redirect me over to a source that explains the process, I will appreciate.
#!/bash/sh
myVar = ls ~/bin | grep -c $0
Posting your code at shellcheck.net gives you valuable pointers quickly:
myVar = ls ~/bin | grep -c $0
^-- SC2037: To assign the output of a command, use var=$(cmd) .
^-- SC1068: Don't put spaces around the = in assignments.
^-- SC2086: Double quote to prevent globbing and word splitting.
If we implement these pointers:
myVar=$(ls ~/bin | grep -c "$0")
Also note that your shebang line has an incorrect path - the #! must be followed by the full path to the executing shell's binary.
Resources for learning bash, the most widely used POSIX-compatible shell:
Introduction: http://www.faqs.org/docs/Linux-HOWTO/Bash-Prog-Intro-HOWTO.html
Guide: http://mywiki.wooledge.org/BashGuide
Cheat sheet: http://mywiki.wooledge.org/BashSheet

Extract all variable values in a shell script

I'm debugging an old shell script; I want to check the values of all the variables used, it's a huge ugly script with approx more than 140 variables used. Is there anyway I can extract the variable names from the script and put them in a convenient pattern like:
#!/bin/sh
if [ ${BLAH} ....
.....
rm -rf ${JUNK}.....
to
echo ${BLAH}
echo ${JUNK}
...
Try running your script as follows:
bash -x ./script.bash
Or enable the setting in the script:
set -x
You can dump all interested variables in one command using:
set | grep -w -e BLAH -e JUNK
To dump all the variables to stdout use:
set
or
env
from inside your script.
You can extract a (sub)list of the variables declared in your script using grep:
grep -Po "([a-z][a-zA-Z0-9_]+)(?==\")" ./script.bash | sort -u
Disclaimer: why "sublist"?
The expression given will match string followed by an egal sign (=) and a double quote ("). So if you don't use syntax such as myvar="my-value" it won't work.
But you got the idea.
grep Options
-P --perl-regexp: Interpret PATTERN as a Perl regular expression (PCRE, see below) (experimental) ;
-o --only-matching: Print only the matched (non-empty) parts of a matching line, with each such part on a separate output line.
Pattern
I'm using a positive lookahead: (?==\") to require an egal sign followed by a double quote.
In bash, but not sh, compgen -v will list the names of all variables assigned (compare this to set, which has a great deal of output other than variable names, and thus needs to be parsed).
Thus, if you change the top of the script to #!/bin/bash, you will be able to use compgen -v to generate that list.
That said, the person who advised you use set -x did well. Consider this extension on that:
PS4=':$BASH_SOURCE:$LINENO+'; set -x
This will print the source file and line number before every command (or variable assignment) which is executed, so you will have a log not only of which variables are set, but just where in the source each one was assigned. This makes tracking down where each variable is set far easier.

Resources