Extract just file path from string - linux

I have a file that contains strings in this format:
MD5 (TestImages/IMG_0627.JPG) = 6ed611b3e777c5f7b729fa2f2412d656
I am trying to figure out a way to extract the file path, so that I would get a string like this:
TestImages/IMG_0627.JPG
For a different part of my script, I am using this code to remove everything before and after the brackets, and I could of course do something similar, however I'm sure there is a better way?
shortFile=${line#*MD5 }
shortFile=${shortFile%%)*}
Anyone have any suggestions?

You could use sed but that has the overhead of starting a new process.
echo $line | sed -r 's/MD5 \((.*)\).*/\1/'

Just to throw a non-sed answer onto the pile. (Also slightly cheaper since it avoids the pipeline and sub-shell.)
awk -F '[()]' '{print $2}' <<<"$line"
That said the substring expansion option is a reasonable one if it does what you need. (Though it looks like you missed the ( in the first expansion.)

Another way with cut can be :
echo $line|cut -d "(" -f2|cut -d ")" -f1

sed -e 's/^.*(\([^)]*\)).*$/\1/' < infile.txt

Related

Substring string in bash

I got this string:
xavier.blodot
wisoyo.hadi
And I want this output: firstletter+lastname
xblodot
whadi
Regards!!
You should use this approach:
sed -r 's:(.).*\.(.+):\1\.\2:g' {YOUR_FILE.TXT}
Another bit smaller sed:
sed -E 's/^(.)[^.]+\./\1/' file
xblodot
whadi
Or using awk:
awk -F. '{print substr($1,1,1) $2}' file
xblodot
whadi
The title says in bash, so I’m assuming it must be in bash only (without using sed, awk or other external processes):
while read ns; do
echo "${ns::1}${ns#*.}"
done < the_input_file.txt
Making it more resilient, if needed, is up to you. It depends on how much you (dis)trust the input. This may include, for example, IFS= read -r ns, a check that [[ "$ns" == +([a-z]).+([a-z]) ]], and arbitrary other consistency checks.
name=xavier.blodot
shortened_name="${name:0:1}${name##*.}"
You would have to catch the case, when the name does not contain a period.

sed not working on a variable within a bash script; requesting a file. Simple example

If I declare a variable within a bash script, and then try to operate on it with sed, I keep getting errors. I've tried with double quotes, back ticks and avoiding single quotes on my variable. Here is what I'm essentially doing.
Call my script with multiple parameters
./myScript.sh apples oranges ilike,apples,oranges,bananas
My objective is to use sed to replace $3 "," with " ", then use wc -w to count how many words are in $3.
MyScript.sh
fruits="$3"
checkFruits= sed -i 's/,/ /g' <<< "$fruits"
echo $checkFruits
And the result after running the script in the terminal:
ilike,apples,oranges,bananas
sed: no input files
P.s. After countless google searches, reading suggestions and playing with my code, I simply cannot get this easy sample of code to work and I'm not really sure why. And I can't try to implement the wc -w until I move past this block.
You can do
fruits="$3"
checkFruits="${3//,/ }"
# or
echo "${3//,/ }"
The -i flag to sed requires a file argument, without it the sed command does what you expect.
However, I'd consider using tr instead of sed for this simple replacement:
fruits="$3"
checkFruits="$(tr , ' ' <<< $fruits)"
echo $checkFruits
Looking at the larger picture, do you want to count comma-separated strings, or the number of words once you have changed commas into spaces? For instance, do you want the string "i like,apples,oranges,and bananas" to return a count of 4, or 6? (This question is moot if you are 100% sure you will never have spaces in your input data.)
If 6, then the other answers (including mine) will already work.
However, if you want the answer to be 4, then you might want to do something else, like:
fruits="$3"
checkFruits="$(tr , \\n <<< $fruits)"
itemCount="$(wc -l <<< $checkFruits)"
Of course this can be condensed a little, but just throwing out the question as to what you're really doing. When asking a question here, it's good to post your expected results along with the input data and the code you've already used to try to solve the problem.
The -i option is for inplace editing of input file, you don't need it here.
To assign a command's output to a variable, use command expansion like var=$(command).
fruits="$3"
checkFruits=$(sed 's/,/ /g' <<< "$fruits")
echo $checkFruits
You don't need sed at all.
IFS=, read -a things <<< "$3"
echo "${#things[#]}"

Bash - Split dir string

I got the following string: '/transfer/IN/name/test.txt'
Now I'm trying to split this for the string name, cause I need it for further operations.
How can I split this correctly?
I've tried with cut (would sed be better?), but I'm not able to find the right approach.
Thanks for your help in advance.
This should help too:
awk -F'/' '{print $(NF-1)}' <<<"/a/b/c/d"
And it outputs:
c
If you like using sed:
sed 's#/[^/]*$##;s#.*/##' <<<"/a/b/c/d"
Just use the proper tools dirname and basename chained together:
echo $(basename $(dirname /transfer/IN/name/test.txt))
dirname => /transfer/IN/name
basename => name
sed solution looks more complex BTW:
sed -e "s#.*/\([^/]*\)/[^/]*#\1#" -e "s#/.*##" <<< name/test.txt
(2 expressions to handle the full relative case name/test.txt)
You can use Parameter expansion:
#!/bin/bash
path=/transfer/IN/name/test.txt
path1=${path%/*} # Remove everything from the last /.
path1=${path1##*/} # Remove everything up to the last /.
echo "$path1"

Why am I getting this error when trying to use sed command to delete string?

I am trying to use sed to delete a string from a given file. The string to be removed is stored in password. Here is what I have
sed -i "s/$password//g" shadowCopy.txt
It keeps telling me
sed: -e expression #1, char 0: no previous regular expression
I understand that it is yelling at me for the blank in the spot designated for the replacement regular expression, but I don't want to replace it with anything. Lots of looking online says that I'm doing it the way i should be. Any guesses?
I have also tried blank=""
sed -i "s/$password/$blank/g" shadowCopy.txt which gives me the same error. I have also looked at maybe using awk somehow, but cant figure out a way. Really any suggestion as to a way to delete a string in a file will satisfy
EDIT: Using the suggestion below my code is as follows
#Retrieve the root password hash from shadowCopy
password= awk -F: '$1=="root" {print $2}' shadowCopy.txt
#Remove the root password
pw="$password" perl -pe 'BEGIN { $search = quotemeta($ENV{pw}); } s/$search//g' shadowCopy.txt
and my output is
$1$aj/Pot/V$H4A7chbz7rfsRIrdL7GO61 //This is the password
root:$1$aj/Pot/V$H4A7chbz7rfsRIrdL7GO61:16469:0:99999:7:::
bin:*:16229:0:99999:7:::
Why is the password being printed out? And obviously when the file contents are dumped to show the changes, the password is still there. If i add echo $password nothing prints so clearly it isn't being properly intialized. Obviously the code in my assignment line works somewhat as it prints out what i'm wanting but it isnt storing it in the variable
RESOLVED: cp shadowCopy.txt shadowCopy.txt~ && awk 'BEGIN{FS=OFS=":"} $1=="root"{$2=""}1' shadowCopy.txt~ > shadowCopy.txt && rm shadowCopy.txt~ is what actually ended up doing it for me. In case anyone in the future cares to know
The problem is that sed cannot operate on strings, only on regexps with some additional restrictions. This will work:
awk -v tgt="$password" 's=index($0,tgt){$0 = substr($0,1,s-1) substr($0,s+length(tgt)}1' file
because it's using only string operations.
Given your newly posted information, you want this:
awk 'BEGIN{FS=OFS=":"} $1=="root"{$2=""} 1' shadowCopy.txt > tmp$$ &&
mv tmp$$ shadowCopy.txt
or if you have GNU awk and care about not naming the tmp file:
awk -i inplace 'BEGIN{FS=OFS=":"} $1=="root"{$2=""} 1' shadowCopy.txt
It happens when your variable is resolved to an empty string. Look:
p="a" && sed "s/$p/?/g" infile
That yields:
J?n 16 08:33:18 m?il.
And:
p="" && sed "s/$p//" infile
That yields:
sed: -e expression #1, char 0: no previous regular expression

Linux command line: split a string

I have long file with the following list:
/drivers/isdn/hardware/eicon/message.c//add_b1()
/drivers/media/video/saa7134/saa7134-dvb.c//dvb_init()
/sound/pci/ac97/ac97_codec.c//snd_ac97_mixer_build()
/drivers/s390/char/tape_34xx.c//tape_34xx_unit_check()
(PROBLEM)/drivers/video/sis/init301.c//SiS_GetCRT2Data301()
/drivers/scsi/sg.c//sg_ioctl()
/fs/ntfs/file.c//ntfs_prepare_pages_for_non_resident_write()
/drivers/net/tg3.c//tg3_reset_hw()
/arch/cris/arch-v32/drivers/cryptocop.c//cryptocop_setup_dma_list()
/drivers/media/video/pvrusb2/pvrusb2-v4l2.c//pvr2_v4l2_do_ioctl()
/drivers/video/aty/atyfb_base.c//aty_init()
/block/compat_ioctl.c//compat_blkdev_driver_ioctl()
....
It contains all the functions in the kernel code. The notation is file//function.
I want to copy some 100 files from the kernel directory to another directory, so I want to strip every line from the function name, leaving just the filename.
It's super-easy in python, any idea how to write a 1-liner in the bash prompt that does the trick?
Thanks,
Udi
cat "func_list" | sed "s#//.*##" > "file_list"
Didn't run it :)
You can use pure Bash:
while read -r line; do echo "${line%//*}"; done < funclist.txt
Edit:
The syntax of the echo command is doing the same thing as the sed command in Eugene's answer: deleting the "//" and everything that comes after.
Broken down:
"echo ${line}" is the same as "echo $line"
the "%" deletes the pattern that follows it if it matches the trailing portion of the parameter
"%" makes the shortest possible match, "%%" makes the longest possible
"//*" is the pattern to match, "*" is similar to sed's ".*"
See the Parameter Expansion section of the Bash man page for more information, including:
using ${parameter#word} for matching the beginning of a parameter
${parameter/pattern/string} to do sed-style replacements
${parameter:offset:length} to retrieve substrings
etc.
here's a one liner in (g)awk
awk -F"//" '{print $1}' file
Here's one using cut and rev
cat file | rev | cut -d'/' -f2-| rev

Resources