How to read lines in bash and delimit them by a specified delimiter? [duplicate] - bash

This question already has answers here:
How do I split a string on a delimiter in Bash?
(37 answers)
Closed 7 years ago.
I need to write a script with the following behaviour:
$ echo $'one&some text\ntwo&other text' | ./my_script.sh --delimiter &
Line:
1st: one
2nd: some tex
Line:
1st: two
2nd: other text
Which can be also called with the default delimiter which is \t:
$ echo $'one\tsome text\nfive\tother text' | ./my_script.sh
Output should be the same as above.
Script should take input via standard in.
What is the easiest way to do this? Possibly in pure bash.
I've tried this approach but it does not work and I don't know why:
while read -r line
do
echo "$line"
IFS=$DELIMITER
arr=(${line//$DELIMITER/ })
echo ${arr[0]}
echo ${arr[1]}
done

You can do it in bash without using external programs.
$ cat script.sh
#!/bin/bash
if [ "$1" = "--delimiter" ]
then
d=$2
else
d=$'\t'
fi
while IFS="$d" read -r first rest; do
echo "1st: $first"
echo "2nd: $rest"
done
$ echo $'one\tsome text\nfive\tother text' | ./script.sh
1st: one
2nd: some text
1st: five
2nd: other text
$ echo $'one&some text\nfive&other text' | ./script.sh --delimiter \&
1st: one
2nd: some text
1st: five
2nd: other text
Note that the ampersand symbol must be escaped (or quoted) otherwise it will execute the command in the background.

awk to the rescue...
echo -e "one&some text\ntwo&other text" | awk
`BEGIN {
n=spit("st,nd,rd,th",s,",")
}
{ print "Line: ";
c=split($0,r,"&");
for(i=1;i<=c;i++)
print i s[(i%10)%n] ": " r[i]
}
will give
Line:
1st: one
2nd: some text
Line:
1st: two
2nd: other text
Note that this simple suffix lookup will breakdown for 11-13

Related

Get substring after a special character [duplicate]

This question already has answers here:
Extract filename and extension in Bash
(38 answers)
Closed 7 months ago.
I have many strings that look like the following:
word1.word2.word3.xyz
word1.word2.word3.word4.abc
word1.word2.mno
word1.word2.word3.pqr
Using bash, I would like to just get the string after the last '.'(dot) character.
So the output I want:
xyz
abc
mno
pqr
Is there any way to do this?
AWK will do it. I'm using GNU AWK:
$ awk -F '.' '{print $NF}' <<EOF
word1.word2.word3.xyz
word1.word2.word3.word4.abc
word1.word2.mno
word1.word2.word3.pqr
EOF
xyz
abc
mno
pqr
AWK splits lines into fields and we use -F to set the field separator to .. Fields are indexed from 1, so $1 would get the first one (e.g. word1 in the first line) and we can use the variable $NF (for "number of fields") to get the value of the last field in each line.
https://www.grymoire.com/Unix/Awk.html is a great tutorial on AWK.
You can then just use a for loop to iterate over each of the resulting lines:
$ lines=$(awk -F '.' '{print $NF}' <<EOF
word1.word2.word3.xyz
word1.word2.word3.word4.abc
word1.word2.mno
word1.word2.word3.pqr
EOF
)
$ for line in $lines; do echo $line; done
xyz
abc
mno
pqr
I'm using command substitution here - see the Advanced Bash Scripting Guide for information on loops, command substitution and other useful things.
One simple solution would be to split the string on . and then get the last item from the splitted array
lines=(word1.word2.word3.xyz word1.word2.word3.xyz word1.word2.word3.word4.abc word1.word2.mno word1.word2.word3.pqr abcdef 'a * b')
for line in "${lines[#]}"
do
line_split=(${line//./ })
echo "${line_split[-1]}"
done
Another clean shell-checked way would be (the idea is the same)
lines=(word1.word2.word3.xyz word1.word2.word3.xyz word1.word2.word3.word4.abc word1.word2.mno word1.word2.word3.pqr abcdef)
for line in "${lines[#]}"; do
if [[ $line == *.* ]]; then # check if line contains dot character
IFS=. read -r -a split_array <<<"$line" # one-line solution
echo "${split_array[-1]}" # shows the results
else
echo "No dot in string: $line"
fi
done
This is a one-liner solution (after array assignment), without using an explicit loop (but using printf's implicit loop).
arr=( 'word1.word2.word3.xyz'
'word1.word2.word3.word4.abc'
'word1.word2.mno'
'word1.word2.word3.pqr' )
printf '%s\n' "${arr[#]##*.}"

How to parse multiple line output as separate variables

I'm relatively new to bash scripting and I would like someone to explain this properly, thank you. Here is my code:
#! /bin/bash
echo "first arg: $1"
echo "first arg: $2"
var="$( grep -rnw $1 -e $2 | cut -d ":" -f1 )"
var2=$( grep -rnw $1 -e $2 | cut -d ":" -f1 | awk '{print substr($0,length,1)}')
echo "$var"
echo "$var2"
The problem I have is with the output, the script I'm trying to write is a c++ function searcher, so upon launching my script I have 2 arguments, one for the directory and the second one as the function name. This is how my output looks like:
first arg: Projekt
first arg: iseven
Projekt/AX/include/ax.h
Projekt/AX/src/ax.cpp
h
p
Now my question is: how do can I save the line by line output as a variable, so that later on I can use var as a path, or to use var2 as a character to compare. My plan was to use IF() statements to determine the type, idea: IF(last_char == p){echo:"something"}What I've tried was this question: Capturing multiple line output into a Bash variable and then giving it an array. So my code looked like: "${var[0]}". Please explain how can I use my line output later on, as variables.
I'd use readarray to populate an array variable just in case there's spaces in your command's output that shouldn't be used as field separators that would end up messing up foo=( ... ). And you can use shell parameter expansion substring syntax to get the last character of a variable; no need for that awk bit in your var2:
#!/usr/bin/env bash
readarray -t lines < <(printf "%s\n" "Projekt/AX/include/ax.h" "Projekt/AX/src/ax.cpp")
for line in "${lines[#]}"; do
printf "%s\n%s\n" "$line" "${line: -1}" # Note the space before the -1
done
will display
Projekt/AX/include/ax.h
h
Projekt/AX/src/ax.cpp
p

Shell script to print the lines which contains a word added by the user

I have a file named data.txt, which contains the following:
1440;150;1000000;pizza;hamburger
1000;180;56124;coke;sprite;water;juice
566;40;10000;cake;pizza;coke
I want to make a program which asks for an input from the user then prints out the lines which contains the given word.
For example:
If I enter coke, it should print out the second and third line. If I enter hambuger it should only print out the first line.
Here is the code that I tried but it doesn't work. Can anybody help me please?
echo "Enter a word"`
read word
while read line; do
numbersinthefile=$(echo $line | cut -d';' -f4);
if [ $numbersinthefile -eq $num ]; then
echo $line;
fi
done
Earlier I forgot to mention that I want the program to allow multiple inputs from the user. Example:
If I type in "pizza sprite", it gives me the first and second line.
That's a simple grep, isn't it?
read -p "Enter a word: " word
grep -F "$word" file
Add -w to match coke with coke only, and not with co or ok.
read -p "Enter a word: " word
grep -Fw "$word" file
Could you please try following once.
cat script.ksh
echo "Please enter word which you want to look for in Input_file:"
read value
awk -v val="$value" '$0 ~ val' Input_file
After running above code following is how it will work.
./script.ksh
Please enter word which you want to look for in Input_file:
coke
1000;180;56124;coke;sprite;water;juice
566;40;10000;cake;pizza;coke
EDIT: In case you want to pass multiple values to script then how about passing them as an arguments to program itself?
cat script.ksh
for var in "$#"
do
awk -v val="$var" '$0 ~ val' Input_file
done
Then run script in following fashion.
script.ksh test coke cake etc
Here is one in awk that accepts partial matches:
$ awk '
BEGIN {
FS=";" # file field sep
printf "Feed me text: " # text for prompt
if((getline s < "-")<=0) # read user input
exit # exit if unsuccessful
}
{
for(i=4;i<=NF;i++) # iterate fields from file records >= 4
if($i~s) { # if match (~ since there was a space in eof NR==3)
print
next # only output each matching record once
}
}' file
Output
Feed me text: coke
1000;180;56124;coke;sprite;water;juice
566;40;10000;cake;pizza;coke

search lines in bash for specific character and display line

I am trying to write search a string in bash and echo the line of that string that contains the + character with some text is a special case. The code does run but I get both lines in the input file displayed. Thank you :)
bash
#!/bin/bash
printf "Please enter the variant the following are examples"
echo " c.274G>T or c.274-10G>A"
printf "variant(s), use a comma between multiple: "; IFS="," read -a variant
for ((i=0; i<${#variant[#]}; i++))
do printf "NM_000163.4:%s\n" ${variant[$i]} >> c:/Users/cmccabe/Desktop/Python27/input.txt
done
awk '{for(i=1;i<=NF;++i)if($i~/+/)print $i}' input.txt
echo "$i" "is a special case"
input.txt
NM_000163.4:c.138C>A
NM_000163.4:c.266+83G>T
desired output ( this line contains a + in it)
NM_000163.4:c.266+83G>T is a special case
edit:
looks like I need to escape the + and that is part of my problem
you can change your awk script as below and get rid of echo.
$ awk '/+/{print $0,"is a special case"}' file
NM_000163.4:c.266+83G>T is a special case
As far as I understand your problem, you can do it with a single sed command:
sed -n '/+/ {s/$/is a special case/ ; p}' input.txt
On lines containing +, it replaces the end ($) with your text, thus appending it. After that the line is printed.

BASH - Reading Multiple Lines from Text File

i am trying to read a text file, say file.txt and it contains multiple lines.
say the output of file.txt is
$ cat file.txt
this is line 1
this is line 2
this is line 3
I want to store the entire output as a variable say, $text.
When the variable $text is echoed, the expected output is:
this is line 1 this is line 2 this is line 3
my code is as follows
while read line
do
test="${LINE}"
done < file.txt
echo $test
the output i get is always only the last line. Is there a way to concatenate the multiple lines in file.txt as one long string?
You can translate the \n(newline) to (space):
$ text=$(tr '\n' ' ' <file.txt)
$ echo $text
this is line 1 this is line 2 this is line 3
If lines ends with \r\n, you can do this:
$ text=$(tr -d '\r' <file.txt | tr '\n' ' ')
Another one:
line=$(< file.txt)
line=${line//$'\n'/ }
test=$(cat file.txt | xargs)
echo $test
You have to append the content of the next line to your variable:
while read line
do
test="${test} ${LINE}"
done < file.txt
echo $test
Resp. even simpler you could simply read the full file at once into the variable:
test=$(cat file.txt)
resp.
test=$(tr "\n" " " < file.txt)
If you would want to keep the newlines it would be as simple as:
test=<file.txt
I believe it's the simplest method:
text=$(echo $(cat FILE))
But it doesn't preserve multiple spaces/tabs between words.
Use arrays
#!/bin/bash
while read line
do
a=( "${a[#]}" "$line" )
done < file.txt
echo -n "${a[#]}"
output:
this is line 1 this is line 2 this is line 3
See e.g. tldp section on arrays

Resources