bash | variable in variable - bash

I want to get version number of tomcat.tar.gz file like this
read -p echo " Enter Version (8 or 9)" version
version8=$(printf -- '%s\n' * | grep -oP 'apache-tomcat-$version\K.*(?=\.tar\.gz)')
version9=$(printf -- '%s\n' * | grep -oP 'apache-tomcat-$version\K.*(?=\.tar\.gz)')
echo $version8 #or better $version${version}, but that doesn't work, too
depending on which version the user entered, I will receive the version number from the gz-file in the current folder.
Example:
in my folder are two tar.gz
apache-tomcat-8.5.78.tar.gz
apache-tomcat-9.0.56.tar.gz
Starting the script:
Enter Version (8 or 9): 8
output should be: 8.5.78
With the above code I am getting nothing. What's wrong with it? I suspect it is due to the variable (version) within a variable (version8). How is it syntactically correct?

I have this working with awk if you are interested, as follows:
read -p "Enter Version (8 or 9) " version
ls *.gz | awk "{split(\$0,a,\"-\"); split(a[3],b,\".\"); split(a[3],c,\".tar\"); if (b[1] == \"$version\") {print c[1]}}"

Related

echo working in a very different way

Here PLUGIN=ABC
$ echo "{\"PluginName\": \"${PLUGIN}\""
""PluginName": "ABC
$ echo "{\"PluginName\":${PLUGIN}\",\"Filename\":\"${VAR}\" , \"ErrorString\":"
","Filename":"ABC" , "ErrorString":eployerProps
However if I change above variable PLUGIN to any other string its working.
$ echo "{\"PluginName\":\"${PLUGINS}\",\"Filename\":\"${VAR}\" , \"ErrorString\":"
{"PluginName":"ABC","Filename":"ABC" , "ErrorString":
Not able to understand whats the reason. This is bash 4 however on other server its working fine.
I cannot reproduce your problem. This is what my bash 4.4.23(1) prints:
$ PLUGIN=ABC
$ echo "{\"PluginName\": \"${PLUGIN}\""
{"PluginName": "ABC"
However if I change above variable PLUGIN to any other string its working.
Have you noticed that your second command differs from the first one?
echo "{\"PluginName\":${PLUGIN}\",\"Filename\":\"${VAR}\" , \"ErrorString\":"
| |
different | \ different
| |
echo "{\"PluginName\":\"${PLUGINS}\",\"Filename\":\"${VAR}\" , \"ErrorString\":"
However, you could make your life a lot easier by using printf:
$ PLUGIN=ABC
$ VAR=XYZ
$ printf '{"PluginName": "%s"\n' "$PLUGIN"
{"PluginName": "ABC"
$ printf '{"PluginName":"%s","Filename":"%s","ErrorString":\n' "$PLUGIN" "$VAR"
{"PluginName":"ABC","Filename":"XYZ","ErrorString":
or even better for a general approach:
$ printf '{'; printf '"%s":"%s",' PluginName "$PLUGIN" Filename "$VAR"
{"PluginName":"ABC","Filename":"XYZ",
Here PLUGIN=ABC
No, that would not explain the output you're seeing. It's much more likely that PLUGIN=$'ABC\r' (i.e. A B C followed by a carriage return).
Carriage return moves the cursor back to the beginning of the line when printed to a terminal, which is why your output looks so confusing.
Try echo "$PLUGIN" | cat -v or echo "$PLUGIN" | xxd (or any other hex dump tool) to see what's actually in there.
But not able to do on a specific server only.
If PLUGIN is the result of reading a line from a file, then this file is probably in Windows/DOS format on that server (with Carriage Return / Line Feed endings) instead of Unix format (Line Feed only).

Extract the first character after the first number

Let's say I have a file like this :
14-Hello14657
156:Good morning 487
1478456=Good bye 1 2
I would like to extract the first character after the first number of the line (and store it in a variable, one at a time). In this example, it would extract
-
:
=
I guess that I should probably use regular expressions but I am still learning it and I can't find a way to do this.
sed approach:
s="156:Good morning 487"
var1=$(sed 's/^[0-9]*\([^0-9]\).*/\1/' <<< $s)
echo $var1
:
Another approach is bash variable expansion + cut command:
s="1478456=Good bye 1 2"
echo ${s//[[:digit:]]/} | cut -c1
=
With GNU grep (the one installed on most Linux systems) you can use
grep -Po '^[0-9]+\K.' yourFile
To store the output in a variable, use
myVar="$(grep -Po '^[0-9]+\K.' yourFile)"
Using your example, the variable myVar will contain all three symbols:
-
:
=

Using the first column of a file as input in a script

I am having some problems with using the first column ${1} as input to a script.
Currently the portions of the script looks like this.
#!/bin/bash
INPUT="${1}"
for NAME in `cat ${INPUT}`
do
SIZE="`du -sm /FAServer/na3250-a/homes/${NAME} | sed 's|/FAServer/na3250-a/homes/||'`"
DATESTAMP=`ls -ld /FAServer/na3250-a/homes/${NAME} | awk '{print $6}'`
echo "${SIZE} ${DATESTAMP}"
done
However, I want to modify the INPUT="${1}" to take the first {1} within a specific file. This is so I can run the lines above in another script and use a file that is previously generated as the input. Also to have the output go out to a new file.
So something like:
INPUT="$location/DisabledActiveHome ${1}" ???
Here's my full script below.
#!/bin/bash
# This script will search through Disabled Users OU and compare that list of
# names against the current active Home directories. This is to find out
# how much space those Home directories take up and which need to be removed.
# MUST BE RUN AS SUDO!
# Setting variables for _adm and storage path.
echo "Please provide your _adm account name:"
read _adm
echo "Please state where you want the files to be generated: (absolute path)"
read location
# String of commands to lookup information using ldapsearch
ldapsearch -x -LLL -h "REDACTED" -D $_adm#"REDACTED" -W -b "OU=Accounts,OU=Disabled_Objects,DC="XX",DC="XX",DC="XX"" "cn=*" | grep 'sAMAccountName'| egrep -v '_adm$' | cut -d' ' -f2 > $location/DisabledHome
# Get a list of all the active Home directories
ls /FAServer/na3250-a/homes > $location/ActiveHome
# Compare the Disabled accounts against Active Home directories
grep -o -f $location/DisabledHome $location/ActiveHome > $location/DisabledActiveHome
# Now get the size and datestamp for the disabled folders
INPUT="${1}"
for NAME in `cat ${INPUT}`
do
SIZE="`du -sm /FAServer/na3250-a/homes/${NAME} | sed 's|/FAServer/na3250-a/homes/||'`"
DATESTAMP=`ls -ld /FAServer/na3250-a/homes/${NAME} | awk '{print $6}'`
echo "${SIZE} ${DATESTAMP}"
done
I'm new to all of this so any help is welcome. I will be happy to clarify any and all questions you might have.
EDIT: A little more explanation because I'm terrible at these things.
The lines of code below came from a previous script are a FOR loop:
INPUT="${1}"
for NAME in `cat ${INPUT}`
do
SIZE="`du -sm /FAServer/na3250-a/homes/${NAME} | sed 's|/FAServer/na3250-a/homes/||'`"
DATESTAMP=`ls -ld /FAServer/na3250-a/homes/${NAME} | awk '{print $6}'`
echo "${SIZE} ${DATESTAMP}"
done
It is executed by typing:
./Script ./file
The FILE that is being referenced has one column of user names and no other data:
User1
User2
User3
etc.
The Script would take the file and look at the first users name, which is reference by
INPUT=${1}
then run a DU command on that user and find out what the size of their HOME drive is. That would be reported by the SIZE variable. It will do the same thing with the DATESTAMP in regards to when the HOME drive was created for the user. When it is done doing the tasks for that user, it would move on to the next one in the column until it is done.
So following that logic, I want to automate the entire process. Instead of doing this in two steps, I would like to make this all a one step process.
The first process would be to generate the $location/DisabledActiveHome file, which would have all of the disabled users names. Then to run the last portion to get the Size and creation date of each HOME drive for all the users in the DisabledActiveHome file.
So to do that, I need to modify the
INPUT=${1}
line to reflect the previously generated file.
$location/DisabledActiveHome
I don't understand your question really, but I think you want this. Say your file is called file.txt and looks like this:
1 99
2 98
3 97
4 96
You can get the first column like this:
awk '{print $1}' file.txt
1
2
3
4
If you want to use that in your script, do this
while read NAME; do
echo $NAME
done < <(awk '{print $1}' file.txt)
1
2
3
4
Or you may prefer cut like this:
while read NAME; do
echo $NAME
done < <(cut -d" " -f1 file.txt)
1
2
3
4
Or this may suit even better
while read NAME OtherUnwantedJunk; do
echo $NAME
done < file.txt
1
2
3
4
This last, and probably best, solution above uses IFS, which is bash's Input Field Separator, so if your file looked like this
1:99
2:98
3:97
4:96
you would do this
while IFS=":" read NAME OtherUnwantedJunk; do
echo $NAME
done < file.txt
1
2
3
4
INPUT="$location/DisabledActiveHome" worked like a charm. I was confused about the syntax and the proper usage and output

How can I select the filename with the highest version number?

I wrote a build script and would like to be able to select the latest version of the script when it installs, e.g. the package name is package_X.X.X.tar.gz and there are multiple copies.
Is there a way to point the build command to package_Y.tar.gz? where Y=max(X.X.X)?
If the files are equal except for the version numbers, you could use something like
ls -v | tail -n 1
From the man-page of ls:
...
-v natural sort of (version) numbers within text
...
Example usage:
$ ls
package_1.5.7.9.tar.gz package_2.5.3.9.tar.gz package_4.6.1.0.tar.gz
$ ls -v | tail -n 1
package_4.6.1.0.tar.gz

this one-line shell script not working on Mac - any ideas how to fix?

This unix command I haven't got quite working on Mac yet - any ideas what needs adjusting:
find . | grep '.*\(css\|js\|rjs\|rhtml\|rb\)$' | sort | while read in; do printf "\n\n####\n# FILE: %s\n####\n\n" ${in} >> onebigfile; cat "${in}" >> onebigfile; done
thanks
The purpose of this command is to gather the content of all the files under the current directory whose names ends as said (css ... rb) in a file named onebigfile (with delimiters) IIUC.
To debug this type of series of piped commands, you can run the individual commands, or individual groups of commands to try to see what is happening. For instance, try:
find .
find . | grep '.*\(css\|js\|rjs\|rhtml\|rb\)$'
find . | grep '.*\(css\|js\|rjs\|rhtml\|rb\)$' | sort
Then get one line of the output (for example ./dir/file.css), and try:
echo './dir/file.css' | while read in; do echo ${in}; done
echo './dir/file.css' | while read in; do cat ${in}; done
echo './dir/file.css' | while read in; do cat ${in} >> onebigfile; done
You should bo able then to understand what's happening.
The problem may be due to file and directory names containing spaces. The solution in this case is to use find -print0 command.

Resources