How to sleep for 1 second between each xargs command? - linux

For example, if I execute
ps aux | awk '{print $1}' | xargs -I {} echo {}
I want to let the shell sleep for 1 second between each echo.
How can I change my shell command?

You can use the following syntax:
ps aux | awk '{print $1}' | xargs -I % sh -c '{ echo %; sleep 1; }'
Be careful with spaces and semicolons though. After every command in between brackets, semicolon is required (even after the last one).

Replace echo by some shell script named sleepecho containing
#!/bin/sh
sleep 1
echo $*

If your awk supports it:
ps aux | awk '{ system("sleep 1"); print $1 }' | xargs -I {} echo {}q
or skip awk and xargs altogether
ps aux | while read -r user rest;
echo $user
sleep 1;
done

Related

Searching a specific file system in bash

I have a task which asks to write a script which displays all partitions formatted with a specific file system, given as parameter.
I have written the script but when i run it it displays '0'. What am i doing wrong?
This is my code:
#!/bin/bash
n=sudo parted -l | tail -n +8 | awk '{print $5}' | wc | awk '{print $2}'
m=sudo parted -l | tail -n +8 | awk '{print $5}'
q=sudo parted -l | tail -n +8
for i in $n; do
if [ "[ $m | sed -n ip ]" = "$1" ]; then
echo "$q | sed -n ip"
fi
done
Different approach from yours, but does it do what you need?
lsblk -f | awk '$0 ~ fs {print $NF}' fs=ext2

Shell command with operator followed by pipes

I want a one line command to grab the most recent restart date from JBoss restart logs. I'm currently using the following, which works
ls -rt $JBOSS_HOME/log/ser* |
xargs grep -ih "Incomplete\s*Deploy" |
awk '{print $1" "$2}' | tail -n 1
Now, I want to add an echo if the grep fails to match anything, i.e.:
ls -rt $JBOSS_HOME/log/ser* |
xargs grep -ih "Incomplete\s*Deploy" ||
echo 'NO RESTART' |
awk '{print $1" "$2}' |
tail -n 1
The problem here is that it seems that the OR operator now causes anything following to go with the failed case. How do I specify that I want to OR (echo) to be printed only when the grep fails? When the grep succeeds it should work like the first command I posted.
Use { to group the terms:
ls -rt $JBOSS_HOME/log/ser* |
xargs grep -ih "Incomplete\s*Deploy" && {
awk '{print $1" "$2}' |
tail -n 1
} ||
echo 'NO RESTART'
or as one line:
ls -rt $JBOSS_HOME/log/ser* | xargs grep -ih "Incomplete\s*Deploy" && { awk '{print $1" "$2}' | tail -n 1; } || echo 'NO RESTART'
No additional subshell required.
You can group commands within a pipe by using parentheses:
ls -rt $JBOSS_HOME/log/ser* | ( xargs grep -ih "Incomplete\s*Deploy" || echo 'NO RESTART' ) | awk '{print $1" "$2}' | tail -n 1
This makes the commands in the parentheses run in a subshell, which from the standpoint of the pipe, makes them work as a single command, i.e. they'll take the input and either print the grep match or 'NO RESTART', and then that will be fed into awk.
res=$(ls -rt $JBOSS_HOME/log/ser* | xargs grep -ih "Incomplete\s*Deploy" | awk '{print $1" "$2}' | tail -n 1)
echo "${res:-NO RESTART}"
Also note that this is not safe for filenames with spaces/etc.

Reformat with awk and sed from STDIN and execute

This is just an example of what I run into a lot:
I would like to copy all .bash_histories to one directory.
grep "/bin/bash" /etc/passwd | awk -F: '{ print "cp " $6"/.bash_history /backup" $6 ".bash_history" }
Output:
cp /home/peter/.bash_history /backup/home/peter/.bash_history
cp /home/john/.bash_history /backup/home/john/.bash_history
What I would like is an output like this:
cp /home/peter/.bash_history /backup/_home_peter_.bash_history
cp /home/john/.bash_history /backup/_home_john_.bash_history
And that this output will be executed.
(It's not specifically about this issue, but just in general how to reformat with awk and sed and execute the new created command line, without really creating a script for it)
The awk script to obtain a similar output will be
grep "/bin/bash" /etc/passwd |head -2 | awk -F: '{ print "cp " $6 "/.bash_history backup/_home_"$1".bash_history" }'
giving an output like
cp /root/.bash_history backup/_home_root.bash_history
cp /home/xxx/.bash_history backup/_home_xxx.bash_history
Now inorder to excecute the commands, the system() function within the awk would be helpfull
system(command) would excecute any command, and return value being the exit status of the command.
The above script can be modified as
grep "/bin/bash" /etc/passwd |head -2 | awk -F: '{ system("cp " $6 "/.bash_history backup/_home_"$1".bash_history;") }'
Test run:
$ grep "/bin/bash" /etc/passwd |head -2 | awk -F: '{ system("cp " $6 "/.bash_history backup/_home_"$1".bash_history;") }'
$ ls backup/
_home_xxx.bash_history _home_root.bash_history
PS: It is not recommend to create directories in your root folder. So i intentionally replaced /backup in your script to backup.
Also inorder for the script to be successful, the backup folder must be created before hand.
getent passwd | grep \/bin\/bash | cut -d ":" -f 6 | while read a; do eval "cp $a/.bash_history /backup/$(echo $a | sed 's#/#_#g')_.bash_history"; done
This uses getent to fetch the passwd file and cut gets the 6th field like your awk statement did, then it reads each entry line by line and builds the string and executes it with eval.
getent passwd | grep \/bin\/bash | cut -d ":" -f 6 | while read a; do eval "cp $a/.bash_history /backup/$(echo $a | sed 's#/#_#g')_.bash_history"; done
Worked perfectly! Issue solved!

What does this command does in shell linux

TMPFILE=/tmp/jboss_ps.$$
${PS} ${PS_OPTS} | \
grep ${JBOSS_HOME}/java | \
egrep -v " grep | \
tee | $0 " | ${AWK} '{print $NF " "}' | \
sort -u > ${TMPFILE} 2>/dev/null
I want to know what this precise line is doing from the code above
egrep -v " grep | \
tee | $0 "
At first i thought that that line is searching for everything that does not contain this exact string "grep | \ tee | $0" but it appears that egrep is processing the pipes, so what's the significance of the pipes here, does it mean OR ? From my test it appears that it's not, but if it means output redirection then what's the inner grep getting ? And why is tee alone too ?
AFAIK
egrep -v " grep | \
tee | $0 "
is nothing but
egrep -v " grep | tee | $0 "
where \ is the continuation character in bash.
egrep is same as grep -E
-v for inverted selection
tee just another string
so egrep -v " grep | tee | $0 " does find lines that have the string {java path} and within this results, all the lines that doesn't match the condition {either of grep OR tee OR $0 } where
$0 is the filename not a '$0' because it uses DOUBLE QUOTES and not single quotes :)
" commands | $variables " has the tendency to expand the variables and use the utility.
The commands in the pipeline before the egrep command is probably something like
ps -ef|grep .... The egrep -v (Option)line you asked about is simply omitting lines you
don't want in the results, in this case the initial grep command issued by the
script, any tee commands and lastly $0 which is the name of the this script
being executed. egrep allows to enter multiple patterns enclosed in double quotes and
separated by pipe symbol. Syntax egrep -[option or not] "patern1|patern2|patern..."

Command substitution as a variable in one-liner

I get the following error:
> echo "${$(qstat -a | grep kig):0:7}"
-bash: ${$(qstat -a | grep kig):0:7}: bad substitution
I'm trying to take the number before. of
> qstat -a | grep kig
1192530.perceus- kigumen lr_regul pbs.sh 27198 2 16 -- 24:00:00 R 00:32:23
and use it as an argument to qdel in openPBS so that I can delete all process that I started with my login kigumen
so ideally, this should work:
qdel ${$(qstat -a | grep kig):0:7}
so far, only this works:
str=$(qstat -a | grep kig); qdel "${str:0:7}"
but I want a clean one-liner without a temporary variable.
The shell substring construct you're using (:0:7) only works on variables, not command substitution. If you want to do this in a single operation, you'll need to trim the string as part of the pipeline, something like one of these:
echo "$(qstat -a | grep kig | sed 's/[.].*//')"
echo "$(qstat -a | awk -F. '/kig/ {print $1}')"
echo "$(qstat -a | awk '/kig/ {print substr($0, 1, 7)}')"
(Note that the first two print everything before the first ".", while the last prints the first 7 characters.) I don't know that any of them are particularly cleaner, but they do it without a temp variable...
qstat -u palle | cut -f 1 -d "." | xargs qdel
Kills all my jobs... normally I grep out the jobname(s) before cut'ing...
So I use a small script "idlist":
qstat -u palle | grep -E "*.in" | grep -E "$1" | cut -f 1 -d "." | xargs
To see all my "map_..." jobs:
idlist "map_*"
For killing all my "map_...." jobs:
idlist "map_*" | xargs qdel
yet another ways :
foreach m1 in $(qstat -a );do
if [[ $m1 =~ kig ]];then
m2=${m1%.kig}
echo "kig found $m2 "
break
fi
done

Resources