How to do something with Bash when a text line appears in a file

Asked
Active3 hr before
Viewed126 times

9 Answers

90%

Isn't the logic in the while loop reversed? This will loop as long as grep finds something, and stop when it doesn't. How about something like until grep -q string file ; do sleep 1s ; done? – Biffen Sep 21 '14 at 14:12 , Thank you for this comment. I've already fixed the ${SLEEP_TIME}. About the naming convention, you are right using lower case seems to be a better idea in order to not override an environment variable. – Xavier S. Sep 21 '14 at 14:04 , Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers ,You can use the q flag while parsing the input via sed. Then sed will interrupt tail as soon as Server started appears in /var/logs/deployment.log.

tail - f path_to_my_log_file.log | sed '/particular_line/ q'
load more v
88%

@penguin359, True, but it'd still be interesting to do it from the command line as well. In my case, there are a variety of different things I'd want to do including many things I can't foresee, so it's convenient to be able to just start the server and do it all in one line. – jonderry Apr 26 '11 at 22:50 , Podcast 392: Do polyglots have an edge when it comes to mastering programming... ,Automatically ending the tail process once it's found.,I have a server log that outputs a specific line of text into its log file when the server is up. I want to execute a command once the server is up, and hence do something like the following:

A simple way would be awk.

tail - f / path / to / serverLog | awk ' /
   Printer is on fire!/ { system("shutdown -h now") } /
   new USB high speed / {
      system("echo \"New USB\" | mail admin")
   }
'

And yes, both of those are real messages from a kernel log. Perl might be a little more elegant to use for this and can also replace the need for tail. If using perl, it will look something like this:

open(my $fd, "<", "/path/to/serverLog") or die "Can't open log";
while (1) {
   if (eof $fd) {
      sleep 1;
      $fd - > clearerr;
      next;
   }
   my $line = < $fd > ;
   chomp($line);
   if ($line = ~/Printer is on fire!/) {
      system("shutdown -h now");
   }
   elsif($line = ~/new USB high speed/) {
      system("echo \"New USB\" | mail admin");
   }
}
load more v
72%

Process or command substitution means nothing more but to run a shell command and store its output to a variable or pass it to another command. The syntax is:,I tried couple of ways reading these records and assigning them a field and print the output to a file like below but nothing is helpful,u can use paste command if the fields are same …..and then output the records to the other file and print another.,can anyone help me to include the line number while read line by line ,

#!/bin/bash

input = "/path/to/txt/file"
while IFS = read - r line
do
   echo "$line"
done < "$input"
load more v
65%

The tagged field appears only once in the output.,lists the beginning of a file to stdout. The default is 10 lines, but a different number can be specified. The command has a number of interesting options. ,Using cut to obtain a listing of the mounted filesystems: cut -d ' ' -f1,2 /etc/mtab,The output of nl is very similar to cat -b, since, by default nl does not list blank lines.

cat list - 1 list - 2 list - 3 | sort | uniq > final.list
# Concatenates the list files,
# sorts them,
# removes duplicate lines,
# and
finally writes the result to an output file.
load more v
75%

I guess everyone knows the useful Linux cmd line utilities head and tail. head allows you to print the first X lines of a file, tail does the same but prints the end of the file. What is a good command to print the middle of a file? something like middle --start 10000000 --count 20 (print the 10’000’000th till th 10’000’010th lines)., 1 @DennisWilliamson: tail -n 10000 print the last 10000 lines. use tail -n +10000 to start print at 10000th line. – cuonglm May 23 '14 at 12:16 ,starts at the ten millionth line from the end of the file, while your "middle" command would seem to start at the ten millionth from the beginning which would be equivalent to:,The problem is that for unsorted files with variable length lines any process is going to have to go through the file counting newlines. There's no way to shortcut that.

sed - n '10000000,10000020p'
filename

You might be able to speed that up a little like this:

sed - n '10000000,10000020p; 10000021q'
filename

By the way, your command

tail - n 10000000 filename | head 10

starts at the ten millionth line from the end of the file, while your "middle" command would seem to start at the ten millionth from the beginning which would be equivalent to:

head - n 10000010 filename | tail 10
load more v
40%

Given a file, name file.txt, out task is to write a bash script which print particular line from a file.,Print a line from multiple files,Writing code in comment? Please use ide.geeksforgeeks.org, generate link and share the link here.,Suppose we have two files, file1.txt and file2.txt, We can use the above commands and print particular line from multiple files by ‘&’.

Content of file.txt:

I
love
reading
articles
at
geeks
for
geeks
awk :
$ > awk '{if(NR==LINE_NUMBER) print $0}'
file.txt
sed :
$ > sed - n LINE_NUMBERp file.txt
head :
$ > head - n LINE_NUMBER file.txt | tail - n + LINE_NUMBER
Here LINE_NUMBER is,
which line number you want to print
awk :
$ > awk '{if(NR==4) print $0}'
file.txt
sed :
$ > sed - n 4 p file.txt
head :
$ > head - n 4 file.txt | tail - n + 4
awk:
$ > awk '{if(NR==4) print $0}'
file1.txt & awk '{if(NR==4) print $0}'
file2.txt
sed:
$ > sed - n 4 p file1.txt & sed - n 4 p file2.txt
head:
$ > head - n 4 file1.txt | tail - n + 4 & head - n 4 file2.txt | tail - n + 4
load more v
22%

0
60%

/# &/g replaces a part, in this case it puts a # in front of the line dictated by the & sign.,While grep can format output on screen, it is unable to modify a file in place. To do this, you’d need a file editor like ed . Since ed is not part of this article, use sed to achieve the same thing you did with grep in the previous article's first example. This time modify the /etc/fstab file in-place passing the -i flag to sed . Without the -i flag , you'd only see what would have been modified.,/^[^#]/ matches everything that is a character and does not start with a hash (#).,Maybe a program generated the wrong format, or it concatenated the fields to one. What if you were only interested in keeping the alpha characters and wanted to discard the digits? How would you achieve this goal with sed?

The simplest sed invocation when substituting foo for bar is:

$ sed 's/foo/bar/'
inputfile
load more v
48%

Perl is a much richer programming language then ksh, but still one can do perl commands from within a ksh script. This might touch Randal, but it's true. Let's say you want to remove all ^M from a file, then take perl for one line in your ksh script:,Every unix command can take it's commands from a text like listing with:,To catch the output of a pipeline each line at a time in a variable use:,Perl can do an infinite amount of things in many different ways. For anything bigger use perl instead of a shell script.

A script has four types of lines: The shell defining line at the top, empty lines, commentary lines starting with a # and command lines. See the following top of a script as an example for these types of lines:

#!/usr/bin/ksh

# Commentary......

   file = /path/file
if [
   [$file = $1]
];
then
command
fi

A command starts with the first word on a line or if it's the second command on a line with the first word after a";'.
A command ends either at the end of the line or whith a ";". So one can put several commands onto one line:

print - n "Name: ";
read name;
print ""


One can continue commands over more than one line with a "\" immediately followed by a newline sign which is made be the return key:

grep filename | sort - u | awk '{print $4}' | \
   uniq - c >> /longpath/file

if then fi

if [
   [$value - eq 7]
];
then
print "$value is 7"
fi
or:

   if [
      [$value - eq 7]
   ]
then
print "$value is 7"
fi
or:

   if [
      [$value - eq 7]
   ];
then print "$value is 7";
fi

if then else fi

if [
   [$name = "John"]
];
then
print "Your welcome, ${name}."
else
   print "Good bye, ${name}!"
fi

if then elif then else fi

if [
   [$name = "John"]
];
then
print "Your welcome, ${name}."
elif[[$name = "Hanna"]];
then
print "Hello, ${name}, who are you?"
else
   print "Good bye, ${name}!"
fi

case esac

case $var in
   john | fred) print $invitation;;
martin) print $declination;;
*) print "Wrong name...";;
esac

while do done

while [
   [$count - gt 0]
];
do
   print "\$count is $count"
   ((count -= 1))
done

until do done

until[[$answer = "yes"]];
do
   print - n "Please enter \"yes\": "
read answer
print ""
done

for var in list do done

for foo in $(ls);
do
   if [
      [-d $foo]
   ];
then
print "$foo is a directory"
else
   print "$foo is not a directory"
fi
done

One can skip the rest of a loop and directly go to the next iteration with: "continue".

while read line
do
   if [
      [$line = * .gz]
   ];
then
continue
else
   print $line
fi
done

One can also prematurely leave a loop with: "break".

while read line;
do
   if [
      [$line = * !(.c)]
   ];
then
break
else
   print $line
fi
done

The number of command line arguments is stored in $# so one can check
for arguments with:

if [
   [$ # - eq 0]
];
then
print "No Arguments"
exit
fi

The single Arguments are stored in $1, ....$n and all are in $* as one string. The arguments cannot
directly be modified but one can reset the hole commandline for another part of the program.
If we need a first argument $first for the rest of the program we do:

if [
   [$1 != $first]
];
then
set $first $ *
   fi

One can iterate over the command line arguments with the help of the shift command. Shift indirectly removes the first argument.

until[[$ # - qe 0]];
do
   # commands....
shift
done

One can also iterate with the for loop, the default with for is $*:

for arg;
do
   print $arg
done

To compare strings one uses "=" for equal and "!=" for not equal.
To compare numbers one uses "-eq" for equal "-ne" for not equal as well as "-gt" for greater than
and "-lt" for less than.

if [
   [$name = "John"]
];
then
# commands....
fi
if [
   [$size - eq 1000]
];
then
# commands....
fi

With "&&" for "AND" and "||" for "OR" one can combine statements:

if [
   [$price - lt 1000 || $name = "Hanna"]
];
then
# commands....
fi
if [
   [$name = "Fred" && $city = "Denver"]
];
then
# commands....
fi

One can make one in either of the following two ways:

function foo {
   # commands...
}

foo() {
   # commands...
}

To get each line of a file into a variable iteratively do:

{
   while read myline;
   do
      # process $myline
   done
} < filename

To catch the output of a pipeline each line at a time in a variable use:

last | sort | {
   while read myline;do
      # commands
   done
}
load more v

Other "undefined-undefined" queries related to "How to do something with Bash when a text line appears in a file"