trying to read every line in file, output always 'cat $file' - linux

I am trying to display every line of a file in the terminal but the output is always:
cat $file
this is my code:
#!/bin/bash
file="users.csv"
IFS=''
echo "bobama, Barack Obama" > $file
echo "gbush, George Bush" >> $file
for line in `cat $file`;
do
echo $line;
done

I solved it by replacing 'cat $file' with $(cat $file).
You can find a better explanation here:
Why can't you use cat to read a file line by line where each line has delimiters

Related

How can I keep file name to variable from this code

readLBL.sh
#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
echo "Text read from file: $line"
done < "$1"
When I run this shell script in Terminal and I have to insert file name for run it
Example :
./readLBL.sh science.txt
output :
58050364;Tom Jones
58050365;Marry Jane
how can i keep "science.txt" into some variable like a = "science.txt"
Use $1 as this is the argument you are already using to read the file in the first instance.
#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
echo "Text read from file $1: $line"
done < "$1"
Running this gives the following:
$ ./readLBL.sh science.txt
Text read from file science.txt: 58050364;Tom Jones
Text read from file science.txt: 58050365;Marry Jane
a="science.txt"
from the Linux command line, will set $a equal to science.txt
If you want this permanent, you could perhaps add it to the bottom of one of your linux profiles. For example add it to the bottom of ~/.bashrc

How to read each line of a file 1 at a time in BASH [duplicate]

This question already has answers here:
Looping through the content of a file in Bash
(16 answers)
Closed 2 years ago.
I have the following .txt file:
Marco
Paolo
Antonio
I want to read it line-by-line, and for each line I want to assign a .txt line value to a variable. Supposing my variable is $name, the flow is:
Read first line from file
Assign $name = "Marco"
Do some tasks with $name
Read second line from file
Assign $name = "Paolo"
The following reads a file passed as an argument line by line:
while IFS= read -r line; do
echo "Text read from file: $line"
done < my_filename.txt
This is the standard form for reading lines from a file in a loop. Explanation:
IFS= (or IFS='') prevents leading/trailing whitespace from being trimmed.
-r prevents backslash escapes from being interpreted.
Or you can put it in a bash file helper script, example contents:
#!/bin/bash
while IFS= read -r line; do
echo "Text read from file: $line"
done < "$1"
If the above is saved to a script with filename readfile, it can be run as follows:
chmod +x readfile
./readfile filename.txt
If the file isn’t a standard POSIX text file (= not terminated by a newline character), the loop can be modified to handle trailing partial lines:
while IFS= read -r line || [[ -n "$line" ]]; do
echo "Text read from file: $line"
done < "$1"
Here, || [[ -n $line ]] prevents the last line from being ignored if it doesn't end with a \n (since read returns a non-zero exit code when it encounters EOF).
If the commands inside the loop also read from standard input, the file descriptor used by read can be chanced to something else (avoid the standard file descriptors), e.g.:
while IFS= read -r -u3 line; do
echo "Text read from file: $line"
done 3< "$1"
(Non-Bash shells might not know read -u3; use read <&3 instead.)
I encourage you to use the -r flag for read which stands for:
-r Do not treat a backslash character in any special way. Consider each
backslash to be part of the input line.
I am citing from man 1 read.
Another thing is to take a filename as an argument.
Here is updated code:
#!/usr/bin/bash
filename="$1"
while read -r line; do
name="$line"
echo "Name read from file - $name"
done < "$filename"
Using the following Bash template should allow you to read one value at a time from a file and process it.
while read name; do
# Do what you want to $name
done < filename
#! /bin/bash
cat filename | while read LINE; do
echo $LINE
done
Use:
filename=$1
IFS=$'\n'
for next in `cat $filename`; do
echo "$next read from $filename"
done
exit 0
If you have set IFS differently you will get odd results.
Many people have posted a solution that's over-optimized. I don't think it is incorrect, but I humbly think that a less optimized solution will be desirable to permit everyone to easily understand how is this working. Here is my proposal:
#!/bin/bash
#
# This program reads lines from a file.
#
end_of_file=0
while [[ $end_of_file == 0 ]]; do
read -r line
# the last exit status is the
# flag of the end of file
end_of_file=$?
echo $line
done < "$1"
If you need to process both the input file and user input (or anything else from stdin), then use the following solution:
#!/bin/bash
exec 3<"$1"
while IFS='' read -r -u 3 line || [[ -n "$line" ]]; do
read -p "> $line (Press Enter to continue)"
done
Based on the accepted answer and on the bash-hackers redirection tutorial.
Here, we open the file descriptor 3 for the file passed as the script argument and tell read to use this descriptor as input (-u 3). Thus, we leave the default input descriptor (0) attached to a terminal or another input source, able to read user input.
For proper error handling:
#!/bin/bash
set -Ee
trap "echo error" EXIT
test -e ${FILENAME} || exit
while read -r line
do
echo ${line}
done < ${FILENAME}
Use IFS (internal field separator) tool in bash, defines the character using to separate lines into tokens, by default includes <tab> /<space> /<newLine>
step 1: Load the file data and insert into list:
# declaring array list and index iterator
declare -a array=()
i=0
# reading file in row mode, insert each line into array
while IFS= read -r line; do
array[i]=$line
let "i++"
# reading from file path
done < "<yourFullFilePath>"
step 2: now iterate and print the output:
for line in "${array[#]}"
do
echo "$line"
done
echo specific index in array: Accessing to a variable in array:
echo "${array[0]}"
The following will just print out the content of the file:
cat $Path/FileName.txt
while read line;
do
echo $line
done

replacement in a file only in a fixed line

I am writing a shell script in which I will read a file and will modify it.
there will be occurrence of some string "ABC_1" in multiple lines.
I need to replace it with "XYZ_1" only when there is "OPQ_3" also present in the line else there should be no modification in the line.
please help how can I do replacement if I read a file liken by line.
for FILE in $FILES
do
echo $FILE
while read line
do
if grep -n "OPQ_3" $line
then
sed -i 's/ABC_1/XYZ_2/'
fi
done < $FILE
done
You can use this sed:
sed -i '/OPQ_3\|OPQ_4/s/ABC_1/XYZ_2/' file
Anubhava has the better answer. Here's how you'd write it in bash
for file in $FILES; do
echo "$file"
tmpfile=$(mktemp)
while IFS= read -r line; do
[[ $line == *OPQ_3* ]] && line=${line/ABC_1/XYZ_2/}
echo "$line"
done < "$file" > "$tmpfile"
mv "$tmpfile" "$file"
done
Note IFS= read -r line is the only way to read a line from stdin exactly, without losing any whitespace or special characters.

Removing lines matching a pattern

I want to search for patterns in a file and remove the lines containing the pattern. To do this, am using:
originalLogFile='sample.log'
outputFile='3.txt'
temp=$originalLogFile
while read line
do
echo "Removing"
echo $line
grep -v "$line" $temp > $outputFile
temp=$outputFile
done <$whiteListOfErrors
This works fine for the first iteration. For the second run, it throws :
grep: input file ‘3.txt’ is also the output
Any solutions or alternate methods?
The following should be equivalent
grep -v -f "$whiteListOfErrors" "$originalLogFile" > "$outputFile"
originalLogFile='sample.log'
outputFile='3.txt'
tmpfile='tmp.txt'
temp=$originalLogFile
while read line
do
echo "Removing"
echo $line
grep -v "$line" $temp > $outputFile
cp $outputfile $tmpfile
temp=$tmpfile
done <$whiteListOfErrors
Use sed for this:
sed '/.*pattern.*/d' file
If you have multiple patterns you may use the -e option
sed -e '/.*pattern1.*/d' -e '/.*pattern2.*/d' file
If you have GNU sed (typical on Linux) the -i option is comfortable as it can modify the original file instead of writing to a new file. (But handle with care, in order to not overwrite your original)
Used this to fix the problem:
while read line
do
echo "Removing"
echo $line
grep -v "$line" $temp | tee $outputFile
temp=$outputFile
done <$falseFailures
Trivial solution might be to work with alternating files; e.g.
idx=0
while ...
let next='(idx+1) % 2'
grep ... $file.$idx > $file.$next
idx=$next
A more elegant might be the creation of one large grep command
args=( )
while read line; do args=( "${args[#]}" -v "$line" ); done < $whiteList
grep "${args[#]}" $origFile

Use Bash to Read File Then Do "grep" with The Line Against The File Itself

I am trying to read a file using Linux Bash and then use "grep" to run that line against the file itself. It seems not working to me...
#!/bin/bash
path=$1
while read line
do
var1=$(grep $line $path)
echo $?
exit
done < $path
The $? returns 1. What's going on here?
Use grep -F (fixed string) instead:
var1=$(grep -F "$line" "$path")

Resources