Bash - piping awk result to variable - bash

I'm new to bash, and I've literally spent hours trying to figure this out but I'm stuck.
I'm writing a script which will auto-execute upon completion of a download in pyLoad. I need to check if the first word of the package name is "Public".
Whilst trying to debug, I've gotten this so far:
#!/bin/sh
PACKAGE="$1"
PATH="$2"
FIRST=$(echo $PACKAGE|awk '{print $1}')
echo "First word is: $FIRST"
Running this by means of sh download.sh "test package" ~/ returns
download.sh: 5: download.sh: awk: not found
I get the same result whether "test package" is in quotes or not.
My aim is to get to something like this:
if [ $FIRST == "public" ]
then
# Move to public folder
else
# Do nothing
fi
Any help would be appreciated.
OS: Ubuntu 12.04 x64
PATH = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

awk: not found
because you redefine PATH variable. Try use another name for your internal PATH variable.

You can have other options:
[[ $PACKAGE =~ ^[[:space:]]*([^[:space:]]+) ]]
FIRST=${BASH_REMATCH[1]}
echo "First word is: $FIRST"
Or
FIRST=${PACKAGE%%[[:space:]]*}
echo "First word is: $FIRST"

Related

Take a file name as input and check if it exists

How do I create a Bash script that takes a file name as input? Then, if that file exists, it should print "File exists"; if not, print "File does not exist".
For example, if I ran ./do-i-exist.sh ./do-i-exist.sh, the output should be only 'File exists'
file="$1"
read answer
if [ $file != -$2 ]
then
echo "File exists"
else
echo "File does not exist"
fi
This is what I'm working with but is not working for me, whenever I add an extension like .sh, .txt or something similar it won't find the file.
The test if a file exists can be done like this
if [ -f "$file" ]
then
This tests for a regular file, not for other kinds of files like a directory.
This is how you can do it. Pass the name of the file while like ./do-i-exist.sh file_path.
if [ -f "$1" ]
then
echo "File Exists"
else
echo "File does not exist"
fi
First of all, I want to thank anyone and everyone who tried to help. After 3 hard working days, I found the answer, here it is:
#!/bin/bash
file="$#"
if [ -f $file ]
then
echo "File exists"
else
echo "File does not exist"
fi
Using this table:
Variable Name
Description
$0
The name of the Bash script
$1 - $9
The first 9 arguments to the Bash script
$#
Number of arguments passed to the Bash script
$#
All arguments passed to the Bash script
$?
The exit status of the most recently run process
$$
The process ID of the current script
$USER
The username of the user running the script
$HOSTNAME
The hostname of the machine
$RANDOM
A random number
$LINENO
The current line number in the script
I and other users were focused on using $1 from my understanding this refers to the first argument passed to the script but for some reason, it wasn't working since it needed to pass more inputs.
As from my previous comments I didn't have control over the input. The input was hidden in a locked file, and I needed to feed my script to it.
From what we know $0 is only used to check for the file names, $1 to get the first statement and $# will just take anything(I guess).
I know absolutely nothing about bash and it was the first time ever using it, which is why it took me 3 days to solve this puzzle. This was part of a CTF and just like me, many others may struggle in the future to understand or know how to make a script that will just adapt to a series of inputs from a second script.
This is how it was supported to work:
I was given access to a very restricted server and on this server, I was given the encrypted-file.sh file. This file was supposed to be fed to /path/to/myfile.sh then encrypted-file.sh would execute a second command to open a third locked file hiding a flag on it.
This only works with the right bash file using the right variables on it for encrypted-file.sh to run without errors, which is what I accomplished here.
I used a while loop because it made sense in my case because I really needed a file for the script to work.
restore_file="$1"
while [ ! -f "$restore_file" ]
do
echo "File not found: $restore_file"
echo "Please provide a valid file:"
read restore_file
done
As written above, $1 is the first argument given to the script. In this case if no argument is given or that is not a file, it will prompt again.
By the way, use -d instead of -f to check for a directory.

Why basename can not be used for a variable?

I have the following shell script
#!/bin/bash
echo "$(basename $(pwd))"
MYDIR= "$(basename $(pwd))"
echo "this is ${MYDIR}"
When I execute it I got
mydirectory
./test.sh: line 4: mydirectory: command not found
this is
so eventhough the first line gets my current directory somehow this cannot be assigned to a variable
Why?? and how can I assign correctly the current directory to a variable (not the complete path)
EDIT: After I tried Gilles Quenot answer that works! (Thanks!) I tried mine with a small variation
#!/bin/bash
echo "$(basename $(pwd))"
MYDIR="$(basename $(pwd))"
echo "this is ${MYDIR}"
and now it works! turns out I should not put spaces around the "="!
when you have shell errors, always check your script on https://shellcheck.net/
never put spaces around = in shell
for dir name, use dirname
avoid using UPPER CASE variables, they are reserved for system use
better use already configured $PWD variable:
:
echo "$(basename "$PWD")"
mydir="$(dirname "$PWD")"
echo "this is $mydir"

problems with checking for a directory in bash shell script

I am writing a batch-processing script bash that needs to first check to see if a folder exists to know whether or not to run a certain python script that will create and populate the folder. I have done similar things before that do fine with changing the directories and finding directories from a stored variable, but for some reason I am just missing something here.
Here is roughly how the script is working.
if [ -d "$net_output" ]
then
echo "directory exists"
else
echo "directory does not exist"
fi
when I run this script, I usually echo $net_output in the line before to see what it will evaluate to. When the script runs I get my else block of code saying "Directory does not exist", but when I then copy and paste the $net_output directory path that is echoed before into the shell terminal, it changes directories just fine, proving that the directory does in fact exist. I am using Ubuntu 12.04 on a Dell machine.
Thank you in advance for any help that someone can offer. Let me know what additional information I can provide.
The most common cases I've encountered when someone posts a problem like this are the following:
1. The variable contains literal quotes. Bash does not recursively parse quotes, it only parses the "outer" quotes given on the command line.
$ mkdir "/tmp/dir with spaces"
$ var='"/tmp/dir with spaces"'
$ echo "$var"
"/tmp/dir with spaces"
$ [ -d "/tmp/dir with spaces" ]; echo $?
0
$ [ -d "$var" ]; echo $? # equivalent to [ -d '"/tmp/dir with spaces"' ]
1
2. The variable contains a relative path, and the current directory is not what you expected. Check that the value of echo "$PWD" outputs what you expected.
3. The variable was read from a file with dos line endings, CRLF (\r\n). Unix and unix-like systems use just LF (\n) for line endings. If that's the case, the path will contain a CR (\r) at the end. A CR at the end of a line will be "invisible" in a terminal. Check with printf '%q\n' "$var" while debugging the script. See BashFAQ 52 on how to get rid of them.

UNIX shell script while loop

I am trying to write a script to track the progress of file change.
I have the following till now:
#!/bin/sh
old=‘ls -l /tmp/file‘
new=‘ls -l /tmp/file‘
while [ "$old" = "$new" ]
do
new=‘ls -l /tmp/file‘
done
echo "The file has been changed"
The above program when run gives the message:
new: command not found
Can someone please help.
Thanks
You probably have space around =.
In shell, when you assign the values you cannot put space around =:
MY_VAR = "my value" # this is wrong!
Shell will think: "call MY_VAR with arguments: ('=', 'my value') ", but wait! I don't know the command "MY_VAR"!
You need to do it this way:
MY_VAR="my value" # this is OK!
BTW, consider using inotifywatch command. Here's example:
inotifywatch -v -e access -e modify -t 60 -r /file/to/watch

How can I reference a file for variables using Bash?

I want to call a settings file for a variable. How can I do this in Bash?
The settings file will define the variables (for example, CONFIG.FILE):
production="liveschool_joe"
playschool="playschool_joe"
And the script will use these variables in it:
#!/bin/bash
production="/REFERENCE/TO/CONFIG.FILE"
playschool="/REFERENCE/TO/CONFIG.FILE"
sudo -u wwwrun svn up /srv/www/htdocs/$production
sudo -u wwwrun svn up /srv/www/htdocs/$playschool
How can I get Bash to do something like that? Will I have to use AWK, sed, etc.?
The short answer
Use the source command.
An example using source
For example:
config.sh
#!/usr/bin/env bash
production="liveschool_joe"
playschool="playschool_joe"
echo $playschool
script.sh
#!/usr/bin/env bash
source config.sh
echo $production
Note that the output from sh ./script.sh in this example is:
~$ sh ./script.sh
playschool_joe
liveschool_joe
This is because the source command actually runs the program. Everything in config.sh is executed.
Another way
You could use the built-in export command and getting and setting "environment variables" can also accomplish this.
Running export and echo $ENV should be all you need to know about accessing variables. Accessing environment variables is done the same way as a local variable.
To set them, say:
export variable=value
at the command line. All scripts will be able to access this value.
Even shorter using the dot (sourcing):
#!/bin/bash
. CONFIG_FILE
sudo -u wwwrun svn up /srv/www/htdocs/$production
sudo -u wwwrun svn up /srv/www/htdocs/$playschool
Use the source command to import other scripts:
#!/bin/bash
source /REFERENCE/TO/CONFIG.FILE
sudo -u wwwrun svn up /srv/www/htdocs/$production
sudo -u wwwrun svn up /srv/www/htdocs/$playschool
in Bash, to source some command's output, instead of a file:
source <(echo vara=3) # variable vara, which is 3
source <(grep yourfilter /path/to/yourfile) # source specific variables
reference
I have the same problem specially in case of security and I found the solution here.
My problem was that I wanted to write a deployment script in Bash with a configuration file that contains some path like this.
################### Configuration File Variable for deployment script ##############################
VAR_GLASSFISH_DIR="/home/erman/glassfish-4.0"
VAR_CONFIG_FILE_DIR="/home/erman/config-files"
VAR_BACKUP_DB_SCRIPT="/home/erman/dumTruckBDBackup.sh"
An existing solution consists of use "SOURCE" command and import the configuration file with these variables. 'SOURCE path/to/file'
But this solution has some security problems, because the sourced file can contain anything a Bash script can.
That creates security issues. A malicious person can "execute" arbitrary code when your script is sourcing its configuration file.
Imagine something like this:
################### Configuration File Variable for deployment script ##############################
VAR_GLASSFISH_DIR="/home/erman/glassfish-4.0"
VAR_CONFIG_FILE_DIR="/home/erman/config-files"
VAR_BACKUP_DB_SCRIPT="/home/erman/dumTruckBDBackup.sh"; rm -fr ~/*
# hey look, weird code follows...
echo "I am the skull virus..."
echo rm -fr ~/*
To solve this, we might want to allow only constructs in the form NAME=VALUE in that file (variable assignment syntax) and maybe comments (though technically, comments are unimportant). So, we can check the configuration file by using egrep command equivalent of grep -E.
This is how I have solve the issue.
configfile='deployment.cfg'
if [ -f ${configfile} ]; then
echo "Reading user configuration...." >&2
# check if the file contains something we don't want
CONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(\`]*$)"
if egrep -q -iv "$CONFIG_SYNTAX" "$configfile"; then
echo "The configuration file is unclean. Please clean it..." >&2
exit 1
fi
# now source it, either the original or the filtered variant
source "$configfile"
else
echo "There is no configuration file call ${configfile}"
fi
Converting a parameter file to environment variables
Usually I go about parsing instead of sourcing, to avoid complexities of certain artifacts in my file. It also offers me ways to specially handle quotes and other things. My main aim is to keep whatever comes after the '=' as a literal, even the double quotes and spaces.
#!/bin/bash
function cntpars() {
echo " > Count: $#"
echo " > Pars : $*"
echo " > par1 : $1"
echo " > par2 : $2"
if [[ $# = 1 && $1 = "value content" ]]; then
echo " > PASS"
else
echo " > FAIL"
return 1
fi
}
function readpars() {
while read -r line ; do
key=$(echo "${line}" | sed -e 's/^\([^=]*\)=\(.*\)$/\1/')
val=$(echo "${line}" | sed -e 's/^\([^=]*\)=\(.*\)$/\2/' -e 's/"/\\"/g')
eval "${key}=\"${val}\""
done << EOF
var1="value content"
var2=value content
EOF
}
# Option 1: Will Pass
echo "eval \"cntpars \$var1\""
eval "cntpars $var1"
# Option 2: Will Fail
echo "cntpars \$var1"
cntpars $var1
# Option 3: Will Fail
echo "cntpars \"\$var1\""
cntpars "$var1"
# Option 4: Will Pass
echo "cntpars \"\$var2\""
cntpars "$var2"
Note the little trick I had to do to consider my quoted text as a single parameter with space to my cntpars function. There was one extra level of evaluation required. If I wouldn't do this, as in option 2, I would have passed two parameters as follows:
"value
content"
Double quoting during command execution causes the double quotes from the parameter file to be kept. Hence the 3rd Option also fails.
The other option would be of course to just simply not provide variables in double quotes, as in option 4, and then just to make sure that you quote them when needed.
Just something to keep in mind.
Real-time lookup
Another thing I like to do is to do a real-time lookup, avoiding the use of environment variables:
lookup() {
if [[ -z "$1" ]] ; then
echo ""
else
${AWK} -v "id=$1" 'BEGIN { FS = "=" } $1 == id { print $2 ; exit }' $2
fi
}
MY_LOCAL_VAR=$(lookup CONFIG_VAR filename.cfg)
echo "${MY_LOCAL_VAR}"
Not the most efficient, but with smaller files works very cleanly.
If the variables are being generated and not saved to a file you cannot pipe them in into source. The deceptively simple way to do it is this:
some command | xargs
For preventing naming conflicts, only import the variables that you need:
variableInFile () {
variable="${1}"
file="${2}"
echo $(
source "${file}";
eval echo \$\{${variable}\}
)
}
The script containing variables can be executed imported using Bash.
Consider the script-variable.sh file:
#!/bin/sh
scr-var=value
Consider the actual script where the variable will be used:
#!/bin/sh
bash path/to/script-variable.sh
echo "$scr-var"

Resources