How to assign values in bash after running commands - bash

NAME=aaa/bbbbb:0.1.2
How can I assign the new string?
NEW_VAR=$NAME | sed 's/.*\///' | cut -f1 -d":"

Assuming you are using bash, you don't actually need to shell out to other commands, there is built in string mangling functions:
NEW_VAR=${NAME%%:*}
If you would prefer to, it'll be something like this:
NEW_VAR=$(echo -n $NAME | cut -f1 -d":")

Related

How to use an if statement after grep via pipe

I am trying to find all instances of "type":"FollowEvent", and then within those instances, if the string "actor": is not followed by {, then capture the string enclosed in " that comes immediately after "actor":. Else, capture the string enclosed in " that comes immediately after "login:".
What I have so far:
zgrep -e '"type":"FollowEvent"' /path/to/dir/* | zgrep -o '"actor":(?!{)*' | cut -f2- -d: | cut -d',' -f1 > results_file.txt
What this does:
For all files in /path/to/dir, for all lines that contain "type":"FollowEvent", find "actor:" not followed by {. Then take everything after the :, and before the next ,. Put the results in results_file.txt.
A single line in the files that are being grep'd could look like this:
{"repo":{"url":"https://url","name":"/"},"type":"FollowEvent","public":true,"created_at":"2011-05-29","payload":{"target":{"gravatar_id":"73","id":64,"repos":35,"followers":58,"login":"username3"}},"actor":{"gravatar_id":"06","id":439,"url":"https://url","avatar_url":"https://.png","login":"username4"},"id":"14"}
or like this:
{"repo":{"url":"https://url/","name":"/"},"type":"FollowEvent","public":true,"created_at":"2011-04-01","payload":{"target":{"gravatar_id":"40","repos":2,"followers":1,"login":"username2"},"actor":"username1","actor_gravatar":"de4"},"actor":{"gravatar_id":"de4","id":716,"url":"https://url","avatar_url":"https://.png","login":"username2"},"id":"12"}
What I want:
a file containing only the usernames of actors. Here, I want, in results_file.txt:
username4
username1
Let's say:
JSON='{"repo":{"url":"https://url","name":"/"},"type":"FollowEvent","public":true,"created_at":"2011-05-29","payload":{"target":{"gravatar_id":"73","id":64,"repos":35,"followers":58,"login":"username3"}},"actor":{"gravatar_id":"06","id":439,"url":"https://url","avatar_url":"https://.png","login":"username4"},"id":"14"}'
For a simple answer, I do suggest you to use jq: https://stedolan.github.io/jq/
$ echo "$JSON" | jq -r '. | select(.type=="FollowEvent") | .actor.login'
username4
You can install it in most of distros with the default package manager.
Anyway if you need to do it with GNU tools.
$ echo "$JSON" | grep '"type":"FollowEvent"' | sed 's/.*"login":"\([^"]*\).*/\1/g'
username4

Set User Name and Password from Txt file using bash

I have an env.txt file in the following format:
lDRIVER={ODBC Driver 13 for SQL Server};
PORT=1433;
SERVER=serveename;
DATABASE=db;
UID=username;
PWD=password!
I have a git bash script (.sh) that requires the UID and PWD from that file. I was thinking about getting it by the last/second last line number. How do I do this/ is there a better way (say looking for UID and PWD and assigning the git bash variable that way)
There's lots of ways to do this. You could use awk which I would personally use since it's sort of like an x-acto knife for this type of thing:
uid=$(awk -F"[=;]" '/UID/{print $2}' env.txt)
pwd=$(awk -F"[=;]" '/PWD/{print $2}' env.txt)
Or grep and sed. sed is nice because it allows you to get very specific about the piece of info you want to cut from the line, but it's regex which has its learning curve:
uid=$(grep "UID" env.txt | sed -r 's/^.*=(.*)(;|$)/\1/g' )
pwd=$(grep "PWD" env.txt | sed -r 's/^.*=(.*)(;|$)/\1/g' )
As #JamesK noted in the comments you can use sed and have it do the search instead of grep. This is super nice and I would definitely choose this instead of the grep | sed.
uid=$(sed -nr '/UID/s/^.*=(.*)(;|$)/\1/gp' )
pwd=$(sed -nr '/PWD/s/^.*=(.*)(;|$)/\1/gp' )
Or grep and cut. Bleh... we can all do better, but sometimes we just want to grep and cut and not have to think about it:
uid=$(grep "UID" env.txt | cut -d"=" -f2 | cut -d";" -f1)
pwd=$(grep "PWD" env.txt | cut -d"=" -f2 | cut -d";" -f1)
I definitely wouldn't go by line number though. That looks like and odbc.ini file and the order in which the parameters are listed in each odbc entry are irrelevant.
First rename PWD to something like PASSWORD. PWD is a special variable used by the shell. Even better is to use lowercase variable names for all your own variables.
When the password is without special characters (spaces, $, ), you can
source env.txt
When the password has something special, consider editing the env.txt:
lDRIVER="{ODBC Driver 13 for SQL Server}"
PORT="1433"
SERVER="serveename"
DATABASE="db"
UID="username"
PASSWORD="password!"
When you are only interested in lowercase uid and passwd, consider selecting only the interesting fields and change the keywords to lowercase
source <(sed -rn '/^(UID|PWD)=/ s/([^=]*)/\L\1/p' env.txt)

How to write a shell script that reads all the file names in the directory and finds a particular string in file names?

I need a shell script to find a string in file like the following one:
FileName_1.00_r0102.tar.gz
And then pick the highest value from multiple occurrences.
I am interested in "1.00" part of the file name.
I am able to get this part separately in the UNIX shell using the commands:
find /directory/*.tar.gz | cut -f2 -d'_' | cut -f1 -d'.'
1
2
3
1
find /directory/*.tar.gz | cut -f2 -d'_' | cut -f2 -d'.'
00
02
05
00
The problem is there are multiple files with this string:
FileName_1.01_r0102.tar.gz
FileName_2.02_r0102.tar.gz
FileName_3.05_r0102.tar.gz
FileName_1.00_r0102.tar.gz
I need to pick the file with FileName_("highest value")_r0102.tar.gz
But since I am new to shell scripting I am not able to figure out how to handle these multiple instances in script.
The script which I came up with just for the integer part is as follows:
#!/bin/bash
for file in /directory/*
file_version = find /directory/*.tar.gz | cut -f2 -d'_' | cut -f1 -d'.'
done
OUTPUT: file_version:command not found
Kindly help.
Thanks!
If you just want the latest version number:
cd /path/to/files
printf '%s\n' *r0102.tar.gz | cut -d_ -f2 | sort -n -t. -k1,2 |tail -n1
If you want the file name:
cd /path/to/files
lastest=$(printf '%s\n' *r0102.tar.gz | cut -d_ -f2 | sort -n -t. -k1,2 |tail -n1)
printf '%s\n' *${lastest}_r0102.tar.gz
You could try the following which finds all the matching files, sorts the filenames, takes the last in that list, and then extracts the version from the filename.
#!/bin/bash
file_version=$(find ./directory -name "FileName*r0102.tar.gz" | sort | tail -n1 | sed -r 's/.*_(.+)_.*/\1/g')
echo ${file_version}
I have tried and thats worth working below script line, that You need.
echo `ls ./*.tar.gz | sort | sed -n /[0-9]\.[0-9][0-9]/p|tail -n 1`;
It's unnecessary to parse the filename's version number prior to finding the actual filename. Use GNU ls's -v (natural sort of (version) numbers within text) option:
ls -v FileName_[0-9.]*_r0102.tar.gz | tail -1

Why is while read data; do echo "$data" | cut -d: -f1; done so slow?

To get only the files that git grep prints, I can do
$ git grep "search" | cut -d':' -f1
So I made a short helper script cutg to which I can pipe to and I place at ~/bin/ dir.
#!/bin/sh
while read data; do
echo "$data" | cut -d':' -f1
done
So now I can do
$ git grep "search" | cutg
But it is very slow.
Why so? How do I make it as fast as the 1st command?
The script should be just:
cut -d':' -f1
or (better)
exec cut -d':' -f1
Shell loops are slow—especially if they invoke a process on each iteration, and especially if they're useless.
Your loop reads each line of input, and creates a new cut process for each line. The original one-liner used a single cut process for all the input. Thankfully, you can inherit the script's standard input, and simply write
#!/bin/sh
exec cut -d: -f1 "$#" -
There's no need for your script to do anything at all, except replace itself with an appropriate cut invocation. I included "$#" in case you want to provide additional arguments to cut, but you can safely leave that out if you're sure you don't need it.

using cut on a line having multiple instances of the same delimiter - unix

I am trying to write a generic script which can have different file name inputs.
This is just a small part of my bash script.
for example, lets say folder 444-55 has 2 files
qq.filter.vcf
ee.filter.vcf
I want my output to be -
qq
ee
I tried this and it worked -
ls /data2/delivery/Stack_overflow/1111_2222_3333_23/secondary/444-55/*.filter.vcf | sort | cut -f1 -d "." | xargs -n 1 basename
But lets say I have a folder like this -
/data2/delivery/Stack_overflow/de.1111_2222_3333_23/secondary/444-55/*.filter.vcf
My script's output would then be
de
de
How can I make it generic?
Thank you so much for your help.
Something like this in a script will "cut" it:
for i in /data2/delivery/Stack_overflow/1111_2222_3333_23/secondary/444-55/*.filter.vcf
do
basename "$i" | cut -f1 -d.
done | sort
advantages:
it does not parse the output of ls, which is frowned upon
it cuts after having applied the basename treatment, and the cut ignores the full path.
it also sorts last so it's guaranteed to be sorted according to the prefix
Just move the basename call earlier in the pipeline:
printf "%s\n" /data2/delivery/Stack_overflow/1111_2222_3333_23/secondary/444-55/*.filter.vcf |
xargs -n 1 basename |
sort |
cut -f1 -d.

Resources