Find and change each 1st char of directory in path string - bash

It's my 1st script in bash and I'm making a script that the bitbucket pipeline will use. I'm trying to change each 1st letter of the directory to lowerCase.
E.g.
database/Seeders/Entities/Users/Earnings/UserEarningsReportSeeder
will be changed on
database/seeders/entities/users/earnings/userEarningsReportSeeder
Trying with this but not working properly for me :(
echo "$(echo "$Line" | sed 's/\/[A-Z]/\/L&/g')"

Like this (you was very close):
$ sed 's#/[A-Z]#\L&#g' <<< 'Database/Seeders/EarningsFoo'
The separator can be any ASCII character, here #
Output
database/seeders/earningsFoo

Related

removing hosts from a comma delimited file

I am trying to script a way of removing hosts from the hostgroup file in Nagios Core.
The format of the hostgroup file is:
server1,server2,server3,server4
When removing a server, I need to be able to not only remove the server, but also the comma that follows it. So in my example above, if I am removing server2, the file would result as follows
server1,server3,server4
So I have googled and tested the following which works to remove server2 and a comma after it (I don't know what the b is used for exactly)
sed -i 's/\bserver2\b,//g' myfile
What I want to be able to do is to feed a list of hostnames to a small script to remove a bunch of hosts (and their following comma) with something similar to the following. The problem lies in that placing a variable like $x breaks the script so that nothing happens.
#!/bin/ksh
for x in `cat /tmp/list`
do
sed -i 's/\b${x}\b,//g' myfile
done
I think I am very close on a solution here, but could use a little help. Thanks much in advance for your kind assistance.
Using single quotes tells the shell not to replace the ${x} - it turns off variable interpolation if you want to google for it.
https://www.tldp.org/LDP/abs/html/quotingvar.html. So use double quotes around the sed replacement string instead:
while read -r x; do sed -i "s/\b${x},\b//g" myfile; done < /tmp/list
But since the last field won't have a comma after it, might be a good idea to run two sed commands, one looking for \bword,\b and the other for ,word$ - where \b is a word boundary and $ is the end of line.
while read -r x; do sed -i "s/\b${x},\b//g" myfile; sed -i "s/,${x}$//" myfile ; done < /tmp/list
One other possible boundary condition - what if you have just server2 on a line by itself and that's what you're trying to delete? Perhaps add a third sed, but this one will leave a blank line behind which you might want to remove:
while read -r x
do
sed -i "s/\b${x},\b//g" myfile # find and delete word,
sed -i "s/,${x}$//" myfile # find and delete ,word
sed -i "s/^${x}$//" myfile # find word on a line by itself
done < t
This works quite nicely:
#!/bin/bash
IN_FILE=$1
shift; sed -i "s/\bserver[$#],*\b//g" $IN_FILE; sed -i "s/,$//g" $IN_FILE
if you invoke it like ./remove_server.sh myfile "1 4" for your example file containing server1,server2,server3,server4, you get the following output:
server2,server3
A quick explanation of what it does:
shift shifts the arguments down by one (making sure that "myfile" isn't fed into the regex)
First sed removes the server with the numbers supplied as arguments in the string (e.g. "1 4")
Second sed looks for a trailing comma and removes it
The \b matches a word boundary
This is a great resource for learning about and testing regex: https://regex101.com/r/FxmjO5/1. I would recommend you check it out and use it each time you have a regex problem. It's helped me on so many occasions!
An example of this script working in a more general sense:
I tried it out on this file:
# This is some file containing server info:
# Here are some servers:
server2,server3
# And here are more servers:
server7,server9
with ./remove_server.sh myfile "2 9" and got this:
# This is some file containing info:
# Here are some servers:
server3
# And here are more servers:
server7
Pretty sure there is a pure sed solution for this but here is a script.
#!/usr/bin/env bash
hosts=()
while read -r host; do
hosts+=("s/\b$host,\{,1\}\b//g")
done < /tmp/list
opt=$(IFS=';' ; printf '%s' "${hosts[*]};s/,$//")
sed "$opt" myfile
It does not run sed line-by-line, but only one sed invocation. Just in case, say you have to remove 20+ pattern then sed will not run 20+ times too.
Add the -i if you think the output is ok.
Using perl and regex by setting the servers to a regex group in a shell variable:
$ remove="(server1|server4)"
$ perl -p -e "s/(^|,)$remove(?=(,|$))//g;s/^,//" file
server2,server3
Explained:
remove="(server1|server4)" or "server1" or even "server."
"s/(^|,)$remove(?=(,|$))//g" double-quoted to allow shell vars, remove leading comma, expected to be followed by a comma or the end of string
s/^,// file remove leading comma if the first entry was deleted
Use the -i switch for infile editing.
bash script that reads the servers to remove from standard input, one per line, and uses perl to remove them from the hostfile (Passed as the first argument to the script):
#!/usr/bin/env bash
# Usage: removehost.sh hostgroupfile < listfile
mapfile -t -u 0 servers
IFS="|"
export removals="${servers[*]}"
perl -pi -e 's/,?(?:$ENV{removals})\b//g; s/^,//' "$1"
It reads the servers to remove into an array, joins that into a pipe-separated string, and then uses that in the perl regular expression to remove all the servers in a single pass through the file. Slashes and other funky characters (As long as they're not RE metacharacters) won't mess up the parsing of the perl, because it uses the environment variable instead of embedding the string directly. It also uses a word boundry so that removing server2 won't remove that part of server22.

How to find lines with current date with %d-%h-%Y format assigned to a variable in all files

I have a directory under which i have many access files like:
access
access87681
access98709
Now i am trying grep all those lines with current date in format +%d-%h-%Y.
I have written like below:
tm1=$(date '+%d-%h-%Y')
sed -n '/$tm1/p' $dir/access* > $loc/OUD_Req_Res_matrix_data
I am trying to grep all $dir/access* files with $tm1 which is current date in above date format and pushing them into output file $loc/OUD_Req_Res_matrix_data.
the above code is not working. Please suggest
With tm1=$(date '+%d-%h-%Y') and access-files without spaces, you can use:
sed -n "/${tm1}/p" $dir/access*
When the date has slashes, the sed command would break.
You can escape the slashes with
sed 's#/#\\/#g' <<< "$tm1"
Use this in your command:
sed -n "/$(sed 's#/#\\/#g' <<< "$tm1")/p" $dir/access*

How to grep a portion of file name using grep or sed based on a pattern in shell script

I need to get a portion of file name based on a pattern. The file pattern here is not for checking if the file name matches the pattern exactly. The "?"s represent dates, so it can be in the format of YYYYMMDD, or YYYY-MM-DD, and I don't want to get the dates. I guess for now, I will just try to get the letter portion before or after the date portion based on the pattern.
For example, if the file name pattern and the actual file name are:
*_???????? and file name: ab_cd_20160505_efg.txt
I want to grep the string ab_cd. efg is skipped because it's not part of the pattern.
If the file pattern and the actual file name are:
????-??-??_* and file name: 2016-05-05_abc_def-ghi.csv
(contain both dash and undercore), I want to grep the string abc_def-ghi. The .csv is skipped because we don't care about the file extension, that's why we didn't give .csv in the pattern.
So, can someone let me know how to accomplish these using grep or sed or other command in shell script?
a two step approach
$ pattern=$(sed 's/*/([^0-9.]+)/;s/?/[0-9]/g' <<< '*_????????');
$ sed -r "s/$pattern.*/\1/" <<< 'ab_cd_12345678_efg.txt'
ab_cd
$ pattern=$(sed 's/*/([^0-9.]+)/;s/?/[0-9]/g' <<< '????-??-??_*');
$ sed -r "s/$pattern.*/\1/" <<< '1234-56-78_abc_def-ghi.csv'
abc_def-ghi
note the double quotes in the second sed command to let bash expand the pattern.
This does pretty much the same as karakfa's answer, but in Bash:
extract () {
local pattern="$1"
local fname="$2"
pattern="${pattern//\?/[[:digit:]]}"
pattern="${pattern/\*/([^[:digit:].]+)}"
[[ $fname =~ $pattern ]]
echo "${BASH_REMATCH[1]}"
}
It uses parameter expansion to build a regex pattern by replacing all the ? and *, then matches the filename against that pattern and the printing the first capture group.
For example, the regex generated from *_???????? looks like
([^[:digit:].]+)_[[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]]
The function can be used like this:
$ extract '*_????????' 'ab_cd_20160505_efg.txt'
ab_cd
$ extract '????-??-??_*' '2016-05-05_abc_def-ghi.csv'
abc_def-ghi

Script for removing the words in the line

Is there any script for removing the words in the line for example these:
"my_name/your_name/ours_name/name"
"my_name/name"
I want to remove the words within the double quotes and before the last slash. Whatever the word appear, I need to remove it. After removing, both of them should be:
"name"
To be more specific: I have one folder, in that folder there are multiple files. Each file consists of a header file like #include "my_name/ur_name/name". I want it to be #include "name", because I want to make that header in the current directory.
you can try the below command,
Commmand:
sed -i 's|#include "my_name/ur_name/name"|#include "name"|g' *
Description:
command will replace (#include "my_name/ur_name/name") with (#include "name") into all the files of directory
NOTE:
Command immediately returns "OK" message,But it will take time to perform the internal file operations.
Shell file
Create a file called main.sh and copy this:
#Get parameter.
string=$1
#Explode string to array.
IFS='/' read -a array <<< "$string"
#Get array size.
size=${#array[#]}
#Get last array element.
echo ${array[$size-1]}
BASH usage
Now you can call main.sh with the path between double quotes as a parameter and it will return the last segment.
$bash -f main.sh "my_name/your_name/ours_name/name"
name
$bash -f main.sh "my_name/name"
name
Maybe you should also look at this question: Take the last part of the folder path in shell
A Simple one line will do this
file.txt
"my_name/your_name/ours_name/name"
"my_name/x_name"
Command
sed 's/^"//g' file.txt | awk 'BEGIN {FS="/"} {print $NF}' | sed 's/^/"/g'
Output
"name"
"x_name"

How to remove a part of a string with variable?

I just got into bash so I decided to write my first script. To give you a little background I want to write a script that will back up my Documents folder onto a USB stick whenever I connect the USB stick. (I am aware that software like this exists).
I have two strings at the beginning of the script:
directoryPath="/Users/USER/Documents" # Folder I want to backup
backupPath="/Volumes/backMeUp/main" # Where I want the folder to backup
For loops gives me absolute path to a file like this
/Users/USER/Documents/Comics/Bleach/Volume 004/bleach_031.zip
Until now I was using sed like this
newPath=`echo "$file" | sed "/Users\/USER\/Documents/s//Volumes\/backMeUp\/main/"`
But since I want my script to be more "open" and other-user-friendly I want to get rid of this line and make it some other way.
I also tried this with different syntax
echo $file | sed -e "s/$directoryPath/$backupPath/"
but with no luck.
My question is how can I remove part of a string with $directoryPath and replace it with $backupPath?
basename (and dirname) are your friend(s).
Something like this:
#!/bin/bash
directoryPath="/Users/rojcyk/Documents" # Folder I want to backup
backupPath="/Volumes/backMeUp/main" # Where I want the folder to backup
f=$(basename '/Users/rojcyk/Documents/Comics/Bleach/Volume 004/bleach_031.zip')
echo ${backupPath}/${f}
Updated
#!/bin/bash
directoryPath="/Users/rojcyk/Documents" # Folder I want to backup
backupPath="/Volumes/backMeUp/main" # Where I want the folder to backup
f='/Users/rojcyk/Documents/Comics/Bleach/Volume 004/bleach_031.zip'
# delete shortest match of substring from front of string
new_f=${f#$directoryPath}
echo ${backupPath}${new_f}
Output:
/Volumes/backMeUp/main/Comics/Bleach/Volume 004/bleach_031.zip
Read more about bash string operations here
With bash:
directoryPath="/Users/rojcyk/Documents"
backupPath="/Volumes/backMeUp/main"
f="/Users/rojcyk/Documents/Comics/Bleach/Volume 004/bleach_031.zip"
echo "${backupPath}/${f#$directoryPath}"
Produces
/Volumes/backMeUp/main//Comics/Bleach/Volume 004/bleach_031.zip
The double slash in the middle is OK. If you don't want it: "${backupPath}/${f#$directoryPath/}"
is this what you want?
kent$ cat t
$foo$bar$blah
kent$ sed 's/\$foo/\$xxx/g' t
$xxx$bar$blah
or this?
kent$ echo $foo
/f/o/o
kent$ echo $bar
/b/a/r
kent$ cat t
something /f/o/o
kent$ sed "s:$foo:$bar:" t
something /b/a/r
sed -e "s/$directoryPath/$backupPath/"
You're on the right path, just need to manipulate the two path variables first.
The contents of $directoryPath is /Users/rojcyk/Documents, so your sed command is coming out as sed -e "s//Users/rojcyk/Documents//Volumes/backMeUp/main/". You need to escape the directory slashes so they don't affect the sed command.
Try this:
directoryPathEscaped=`echo $directoryPath | sed -e "s/\\//\\\\\\\\\//g"`
backupPathEscaped=`echo $backupPath| sed -e "s/\\//\\\\\\\\\//g"`
# At this point, directoryPathEscaped is equal to "\/Users\/rojcyk\/Documents"
# Now you can do your original command line, with the new variables.
sed -e "s/$directoryPathEscaped/$backupPathEscaped/"

Resources