"Top" output is truncated when redirect to file ? - linux

My project requires "Top" out to be redirect in a file.
I am running couple of application. When I tun top on telnet I am getting full path of one of my application. It looks like as follows
2079 1952 root R 12296 2% 0% -s=1 -PrjPath="/usr/local/Myproject/Application" -stgMode=1
But when I use following command to redirect the out put to file it gets truncated.
Command:
tope -b -n1
Out put:
2079 1952 root R 12296 2% 0% -s=1 -PrjPath="/usr/local/Myproject/Appl
Can any one tell me why it is truncated ?
How to get it full.
Following is my environment.
Embedded linux kernel v2.6.29.
busyboxy v1.10.4
"top" command is part of busybox.
Thanks in Advance
Bhargav Vyas

Use can use "-c" parameter to display the complete command, and you need to make sure the screen width is wide enough to display it.
Ex:
COLUMNS=512 top -b -n1 -c
One side effect would be, the complete path of the command will be displayed. This cannot be avoided. You should also consider using ps, which is much more customizable.
To display only the command names:
ps -eo pcpu,pid,user,comm | sort -k 1 -r
To display with arguments and path:
ps -eo pcpu,pid,user,args | sort -k 1 -r
and so on.

I had a truncating issue even after using the
-c :Command-line/Program-name toggle
option in batch mode. So I had to specify the output width with -w, like
top -b -n 1 -c -w 200
for example.
From the man page:
-w :Output-width-override as: -w [ number ]
In Batch mode, when used without an argument top will format output
using the COLUMNS= and LINES= environment variables, if set.
Otherwise, width will be fixed at the maximum 512 columns. With an
argument, output width can be decreased or increased (up to 512) but
the number of rows is considered unlimited.
In normal display mode, when used without an argument top will attempt
to format output using the COLUMNS= and LINES= environment variables,
if set. With an argument, output width can only be decreased, not
increased. Whether using environment variables or an argument with
-w, when not in Batch mode actual terminal dimensions can never be exceeded.
Note: Without the use of this command-line option, output width is
always based on the terminal at which top was invoked whether or not
in Batch mode.

Related

Why ip_forward_use_pmtu added in the result of sysctl in linux server

So I did an OS version-up in a linux server, and was seeing if any setting has been changed.
And when I typed "sysctl -a | grep "net.ipv4.ip_forward"
The following line was added,
net.ipv4.ip_forward_use_pmtu = 0
I know that this is because this parameter is in /proc/sys.
But I think if the result of sysctl before upload did not show this line, it was not in /proc/sys before as well, right ?
I know that 0 means " this setting is not applied...So basically it does not do anything.
But why this line is added.
The question is
Is there any possible reason that can add this line?
Thank you, ahead.
Even the question itself "added in the result of sysctl in linux server" is wrong here.
sysctl in the way you invoked it, lists all the entries.
grep which you used to filter those entries "selects" matching texts, if you'd run grep foo against the list:
foo
foobar
both items would be matched. That's exactly what you see but the only difference is instead of "foo" you have "net.ipv4.ip_forward".
Using --color shows that clearly:
Pay attention to the use of fgrep instead of grep because people tend to forget that grep interprets some characters as regular expressions, and the dot . means any character, which might also lead to unexpected matches.

How to use sed command to delete lines without backup file?

I have large file with size of 130GB.
# ls -lrth
-rw-------. 1 root root 129G Apr 20 04:25 syslog.log
So I need to reduce file size by deleting line which starts with "Nov 2" , So I have given the following command,
sed -i '/Nov 2/d' syslog.log
So I can't edit file using VIM editor also.
When I trigger SED command , its creating backup file also. But I don't have much space in root. Please try to give alternate solution to delete particular line from this file without increasing space in server.
It does not create a real backup file. sed is a stream editor. When applied to a file with option -i it will stream that file through the sed process, write the output to a new file (a temporary one), when everything is done, it will rename the new file to the original name.
(There are options to create backup files also, but you didn't give them, so I won't mention that further.)
In your case you have a very large file and don't want to create any copy, however temporary. For this you need to open the file for reading and writing at the same time, then your sed process can overwrite the original. After this, you will have to truncate the file at the end of the writing.
To demonstrate how this can be done, we first perform a test case.
Create a test file, containing lots of lines:
seq 0 999999 > x
Now, lets say we want to remove all lines containing the digit 4:
grep -v 4 1<>x <x
This will open the file for reading and writing as STDOUT (1), and for reading as STDIN. The grep command will read all lines and will output only the lines not containing a 4 (option -v).
This will effectively overwrite the beginning of the original file.
You will not know how long the output is, so after the output the original contents of the file will appear:
…
999991
999992
999993
999995
999996
999997
999998
999999
537824
537825
537826
537827
537828
537829
…
You can use the Unix tool truncate to shorten your file manually afterwards. In a real scenario you will have trouble finding the right spot for this, so it makes sense to count the number of bytes written (using wc):
(Don't forget to recreate the original x for this test.)
(grep -v 4 <x | tee /dev/stderr 1<>x) |& wc -c
This will preform the step above and additionally print out the number of bytes written to the terminal, in this example case the output will be 3653658. Now use truncate:
truncate -s 3653658 x
Now you have the result you want.
If you want to do this in a script, i. e. without interaction, you can use this:
length=$((grep -v 4 <x | tee /dev/stderr 1<>x) |& wc -c)
truncate -s "$length" x
I cannot guarantee that this will work for files >2GB or >4GB on your machine; depending on your operating system (32bit?) and the versions of the installed tools you might run into largefile issues. I'd perform tests with large files first (>4GB as this is typically a limit for many things) and then cross your fingers and give it a try :)
Some caveats you have to keep in mind:
Of course, nobody is supposed to append log entries to that log file while the procedure is running.
Also, any abort during the running of the process (power failure, signal caught, etc.) will leave the file in an undefined state. But re-running the command again after such a mishap will in most cases produce the correct output; some lines might be doubled, but not more than a single line should be corrupted then.
The output must be smaller than the input, of course, otherwise the writing will overtake the reading, corrupting the whole result so that lines which should be there will be missing (or truncated at the start).

sort runs out of memory

I'm using a pipe including sort to merge multiple large textfiles and remove dupes.
I don't have root permissions but the box isn't configured in any way to cut non root privileges further down than default debian jessie.
The box has 32GB RAM and 16GB are in use.
Regardless on how I call sort (GNU sort 8.13) it fills up all the remaining RAM and crashes with "out of memory".
It really fills up all the memory before crashing. I followed the process in top.I tried to explicitly set the max memory usage with the -S parameter ranging from 80% to 10% and from 8G to 500M.
The whole pipe looks similar to:
cat * | tr -cd '[:print:]' |sort {various params tested here} -T /other/tmp/path/ | uniq > ../output.txt
Always the same behavior.
Does anyone know what could cause such issue?
And of course how to solve it?
I found the issue myself. It's fairly easy.
The "tr -cd '[:print:]'" removes line breaks and sort reads line by line.
So it tries to read all the files as one line and the -S parameter can't do its job.

system loads in GNU screen's hardstatus line

I use screen a lot on my Linux. I wanted to change the hardstatus line a bit.
I want to add CPU and Memory usage information to the line but I don't know how.
after some searches in Google all I could find was %l option to add system loads.
my line (which is copied) looks like this:
hardstatus alwayslastline '%{= G}[ %{G}%H %{g}][%= %{= w}%?%-Lw%?%{= R}%n*%f %t%?%{= R}(%u)%?%{= w}%+Lw%?%= %{= g}][ %{y}Load: %l %{g}][%{B}%D %d-% M-%Y %{W}%C:%s %A %{g}]'
and my screen hardstatus line is like this:
now what are the three numbers defined ad load ??
and how can I change them to something like CPU load 28% Mem Load 43% or similar?
To keep it short:
The three numbers stand for average cpu load during the last minute, 5 minutes and 15 minutes where 0 means 0% load and 1.0 means 100% load.
Have a look at this excellent explanation of the cpu load.
For the second question I'm not sure if you can express the system load with only one number in the hardstatus line of screen (I don't think so), but I hope my answer helped a little bit ;-) *Jost
If you haven't heard of the screen command backtick since then, this could be your favourite (http://aperiodic.net/screen/commands:backtick).
You can for example define a series of linux ($BASH or sh) commands which echoes your own calculated load value and your own calculated mem-usage value within the backtick command.
In this example let's assume that you just want to display the second value of the "load average" statistic given by "uptime" (the 5 minutes statistic).
Step 1:
If your "uptime" output would look like this (with a space at the beginning of the line and 2 spaces before "load average:")...
17:04:06 up 3 days, 21:52, 12 users, load average: 0.36, 0.27, 0.21
... you could extract your value like this into the variable cpuLoad (and get rid of the trailing "comma"):
cpuLoad=$(cut -s -d\ -f13 <(uptime))
cpuLoad=${cpuLoad:0:-1}
Step 2:
Similarily you could extract your memory values from the output of the "free" command and do some calculations explained in this fine article which would end up in a variable named memLoad (abbreviated here by "memLoad=...").
Step 3:
Put it all together and echo your output as you would like to see it:
backtick 1 5 5 /bin/bash -c 'cpuLoad=$(cut -s -d\ -f13 <(uptime)); cpuLoad=${cpuLoad:0:-1}; memLoad=...; echo "CPU load ${cpuLoad} Mem Load ${memLoad}" '
This will update every 5 seconds the values in your hardstatus or caption status-lines, using the escape-sequence "%1`" in your "hardstatus string" definition.
For more calculations you will need more space which has to be all on one line. So put it in a shell function and call the function from within your screenrc file:
backtick 1 5 5 /bin/bash -c '_mySystemLoadScreenFunction'
What also did not work for me was using $BASH instead of the full path.
This did NOT work:
backtick 1 5 5 $BASH -c '_mySystemLoadScreenFunction'
Hope, this helps.
Thank you very much for your attention.
To expand on the answer of #richard-gantz, here is my solution to also extract the memory usage from free
backtick 1 1 1 /bin/bash -c 'cpuLoad=$(cut -s -d\ -f16 <(uptime)); cpuLoad=${cpuLoad:0:-1}; memLoad=$(free -g | grep Mem | awk '\''{print $3"/"$2" GB"}'\''); echo "CPU: ${cpuLoad} Mem: ${memLoad}" '
# Display the status line at the bottom
hardstatus on
hardstatus alwayslastline
hardstatus string "%{.kW}%-w%{.bW}%t [%n]%{-}%+w %= %{..R} %1` %{..G} %H %{..Y} %Y/%m/%d %c"
I took his solution for cpuLoad using cut but could not get cut to work with the multiline output from free, hence the solution with grep and awk. I am posting it here, because it took me some time this solution out, so it might be helpful for somebody.
The memory usage is used_mem / total_mem in GB.

How do I increase the /proc/pid/cmdline 4096 byte limit?

For my Java apps with very long classpaths, I cannot see the main class specified near the end of the arg list when using ps. I think this stems from my Ubuntu system's size limit on /proc/pid/cmdline. How can I increase this limit?
For looking at Java processes jps is very useful.
This will give you the main class and jvm args:
jps -vl | grep <pid>
You can't change this dynamically, the limit is hard-coded in the kernel to PAGE_SIZE in fs/proc/base.c:
274 int res = 0;
275 unsigned int len;
276 struct mm_struct *mm = get_task_mm(task);
277 if (!mm)
278 goto out;
279 if (!mm->arg_end)
280 goto out_mm; /* Shh! No looking before we're done */
281
282 len = mm->arg_end - mm->arg_start;
283
284 if (len > PAGE_SIZE)
285 len = PAGE_SIZE;
286
287 res = access_process_vm(task, mm->arg_start, buffer, len, 0);
I temporarily get around the 4096 character command line argument limitation of ps (or rather /proc/PID/cmdline) is by using a small script to replace the java command.
During development, I always use an unpacked JDK version from SUN and never use the installed JRE or JDK of the OS no matter if Linux or Windows (eg. download the bin versus the rpm.bin).
I do not recommend changing the script for your default Java installation (e.g. because it might break updates or get overwritten or create problems or ...)
So assuming the java command is in /x/jdks/jdk1.6.0_16_x32/bin/java
first move the actual binary away:
mv /x/jdks/jdk1.6.0_16_x32/bin/java /x/jdks/jdk1.6.0_16_x32/bin/java.orig
then create a script /x/jdks/jdk1.6.0_16_x32/bin/java like e.g.:
#!/bin/bash
echo "$#" > /tmp/java.$$.cmdline
/x/jdks/jdk1.6.0_16_x32/bin/java.orig $#
and then make the script runnable
chmod a+x /x/jdks/jdk1.6.0_16_x32/bin/java
in case of copy and pasting the above, you should make sure that there are not extra spaces in /x/jdks/jdk1.6.0_16_x32/bin/java and #!/bin/bash is the first line
The complete command line ends up in e.g. /tmp/java.26835.cmdline where 26835 is the PID of the shell script.
I think there is also some shell limit on the number of command line arguments, cannot remember but it was possibly 64K characters.
you can change the script to remove the command line text from /tmp/java.PROCESS_ID.cmdline
at the end
After I got the commandline, I always move the script to something like "java.script" and copy (cp -a) the actual binary java.orig back to java. I only use the script when I hit the 4K limit.
There might be problems with escaped characters and maybe even spaces in paths or such, but it works fine for me.
You can use jconsole to get access to the original command line without all the length limits.
It is possible to use newer linux distributions, where this limit was removed, for example RHEL 6.8 or later
"The /proc/pid/cmdline file length limit for the ps command was previously hard-coded in the kernel to 4096 characters. This update makes sure the length of /proc/pid/cmdline is unlimited, which is especially useful for listing processes with long command line arguments. (BZ#1100069)"
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/6.8_Release_Notes/new_features_kernel.html
For Java based programs where you are just interested in inspecting the command line args your main class got, you can run:
jps -m
I'm pretty sure that if you're actually seeing the arguments truncated in /proc/$pid/cmdline then you're actually exceeding the maximum argument length supported by the OS. As far as I can tell, in Linux, the size is limited to the memory page size. See "ps ww" length restriction for reference.
The only way to get around that would be to recompile the kernel. If you're interested in going that far to resolve this then you may find this post useful: "Argument list too long": Beyond Arguments and Limitations
Additional reference:
ARG_MAX, maximum length of arguments for a new process
Perhaps the 'w' parameter to ps is what you want. Add two 'w' for greater output. It tells ps to ignore the line width of the terminal.

Resources