how to see linux command exec time by each user
With the history command, you can enable timestamps like so:
export HISTTIMEFORMAT='%F %T '
Then when you call history, timestamps are enabled.
Example:
1754 2014-07-10 10:12:24 sed -i '0,/port \([0-9]*\)/{s/port \([0-9]*\)/port 7777/}' test.txt
1755 2014-07-10 10:12:26 cat test.txt
1756 2014-07-10 10:16:54 export HISTTIMEFORMAT='%F %T '
1757 2014-07-10 10:16:55 history
me@owncloud:~$
How can I recall the argument of the previous bash command?
You can use $_
or !$
to recall the last argument of the previous command.
Also Alt + . can be used to recall the last argument of any of the previous commands.
Bash command to archive files daily based on date added
Depending on the method that is used to backup the files, the modified or changed date should reflect the time it was copied - for example if you used cp -p to back them up, the modified date would not change but the changed date would reflect the time of copy.
You can get this information using the stat
command:
stat <filename>
which will return the following (along with other file related info not shown):
Access: 2016-05-28 20:35:03.153214170 -0400
Modify: 2016-05-28 20:34:59.456122913 -0400
Change: 2016-05-29 01:39:52.070336376 -0400
This output is from a file that I copied using cp -p at the time shown as 'change'.
You can get just the change time by calling stat with a specified format:
stat -c '%z' <filename>
2016-05-29 01:39:56.037433640 -0400
or with capital Z for that time in seconds since epoch. You could combine that with the date command to pull out just the date (or use grep, etc)
date -d "`stat -c '%z' <filename>" -I
2016-05-29
The command find
can be used to find files by time frame, in this case using the flags -cmin
'changed minutes', -mmin
'modified minutes', or unlikely, -amin
'accessed minutes'. The sequence of commands to get the minutes since midnight is a little ugly, but it works.
We have to pass find an argument of "minutes since a file was last changed" (or modified, if that criteria works). So first you have to calculate the minutes since midnight, then run find.
min_since_mid=$(echo $(( $(date +%s) - $(date -d "(date -I) 0" +%s) )) / 60 | bc)
Unrolling that a bit:
$(date +%s)
== seconds since epoch until 'now'"(date -I) 0"
== todays date in format "YYYY-MM-DD 0" with 0 indicating 0 seconds into the day$(date -d "(date -I 0" +%s))
== seconds from epoch until today at midnight- Then we (effectively) echo ( $now - $midnight ) / 60 to bc to convert the results into minutes.
The find call is passed the minutes since midnight with a leading '-' indicating up to X minutes ago. A'+' would indicate X minutes or more ago.
find /path/to/base/folder -cmin -"$min_since_mid"
The actual answer
Finally to create a tgz archive of files in the given directory (and subdirectories) that have been changed since midnight today, use these two commands:
min_since_mid=$(echo $(( $(date +%s) - $(date -d "(date -I) 0" +%s) )) / 60 | bc)
find /path/to/base/folder -cmin -"${min_since_mid:-0}" -print0 -exec tar czvf /path/to/new/tarball.tgz {} +
The -print0 argument to find tells it to delimit the files with a null string which will prevent issues with spaces in names, among other things.
The only thing I'm not sure on is you should use the changed time (-cmin), the modified time (-mmin) or the accessed time (-amin). Take a look at your backup files and see which field accurately reflects the date/time of the backup - I would think changed time, but I'm not certain.
Update: changed -"$min_since_mid"
to -"${min_since_mid:-0}" so that if min_since_mid isn't set you won't error out with invalid argument - you just won't get any results. You could also surround the find with an if statement to block the call if that variable isn't set properly.
Using linux' at command - scheduling daily / weekly possible?
at
is the wrong tool for this job.
You're looking for cron
.
8 pm every day would be :
0 20 * * * /bin/execute/this/script.sh
8 pm every monday would be :
0 20 * * 1 /bin/execute/this/script.sh
Is there a special restriction on commands executed by cron?
You have to escape percent signs with a backslash:
0 0 * * * pg_dump DB_NAME > /path/to/dumps/`date +\%Y\%m\%d`.dmp
From man 5 crontab
:
The ‘‘sixth’’ field (the rest of the line) specifies the command to
be
run. The entire command portion of the line, up to a
newline or %
character, will be executed by /bin/sh or by the shell specified in
the
SHELL variable of the crontab file. Percent-signs (%) in the
command,
unless escaped with backslash (\), will be changed into newline
characters, and all data after the first % will be sent to the command
as
standard input. There is no way to split a single command line
onto
multiple lines, like the shell’s trailing "\".
Running a shell script once a day at random time
The best alternative to cron
is probably at
- See
at
man page
Usually, at
reads commands from standard input, but you can give a file of jobs with -f
.
Time wise, you can specify many formats. Maybe in your case the most convenient would be
at -f jobs now + xxx minutes
where your scripts gives xxx as a random value from 1
to 1440
(1440 minutes in a day), and jobs
contains the commands you want to be executed.
Preserve bash history in multiple terminal windows
Add the following to your ~/.bashrc
:
# Avoid duplicates
HISTCONTROL=ignoredups:erasedups
# When the shell exits, append to the history file instead of overwriting it
shopt -s histappend
# After each command, append to the history file and reread it
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"
How do I list all cron jobs for all users?
I ended up writing a script (I'm trying to teach myself the finer points of bash scripting, so that's why you don't see something like Perl here). It's not exactly a simple affair, but it does most of what I need. It uses Kyle's suggestion for looking up individual users' crontabs, but also deals with /etc/crontab
(including the scripts launched by run-parts
in /etc/cron.hourly
, /etc/cron.daily
, etc.) and the jobs in the /etc/cron.d
directory. It takes all of those and merges them into a display something like the following:
mi h d m w user command
09,39 * * * * root [ -d /var/lib/php5 ] && find /var/lib/php5/ -type f -cmin +$(/usr/lib/php5/maxlifetime) -print0 | xargs -r -0 rm
47 */8 * * * root rsync -axE --delete --ignore-errors / /mirror/ >/dev/null
17 1 * * * root /etc/cron.daily/apt
17 1 * * * root /etc/cron.daily/aptitude
17 1 * * * root /etc/cron.daily/find
17 1 * * * root /etc/cron.daily/logrotate
17 1 * * * root /etc/cron.daily/man-db
17 1 * * * root /etc/cron.daily/ntp
17 1 * * * root /etc/cron.daily/standard
17 1 * * * root /etc/cron.daily/sysklogd
27 2 * * 7 root /etc/cron.weekly/man-db
27 2 * * 7 root /etc/cron.weekly/sysklogd
13 3 * * * archiver /usr/local/bin/offsite-backup 2>&1
32 3 1 * * root /etc/cron.monthly/standard
36 4 * * * yukon /home/yukon/bin/do-daily-stuff
5 5 * * * archiver /usr/local/bin/update-logs >/dev/null
Note that it shows the user, and more-or-less sorts by hour and minute so that I can see the daily schedule.
So far, I've tested it on Ubuntu, Debian, and Red Hat AS.
#!/bin/bash
# System-wide crontab file and cron job directory. Change these for your system.
CRONTAB='/etc/crontab'
CRONDIR='/etc/cron.d'
# Single tab character. Annoyingly necessary.
tab=$(echo -en "\t")
# Given a stream of crontab lines, exclude non-cron job lines, replace
# whitespace characters with a single space, and remove any spaces from the
# beginning of each line.
function clean_cron_lines() {
while read line ; do
echo "${line}" |
egrep --invert-match '^($|\s*#|\s*[[:alnum:]_]+=)' |
sed --regexp-extended "s/\s+/ /g" |
sed --regexp-extended "s/^ //"
done;
}
# Given a stream of cleaned crontab lines, echo any that don't include the
# run-parts command, and for those that do, show each job file in the run-parts
# directory as if it were scheduled explicitly.
function lookup_run_parts() {
while read line ; do
match=$(echo "${line}" | egrep -o 'run-parts (-{1,2}\S+ )*\S+')
if [[ -z "${match}" ]] ; then
echo "${line}"
else
cron_fields=$(echo "${line}" | cut -f1-6 -d' ')
cron_job_dir=$(echo "${match}" | awk '{print $NF}')
if [[ -d "${cron_job_dir}" ]] ; then
for cron_job_file in "${cron_job_dir}"/* ; do # */ <not a comment>
[[ -f "${cron_job_file}" ]] && echo "${cron_fields} ${cron_job_file}"
done
fi
fi
done;
}
# Temporary file for crontab lines.
temp=$(mktemp) || exit 1
# Add all of the jobs from the system-wide crontab file.
cat "${CRONTAB}" | clean_cron_lines | lookup_run_parts >"${temp}"
# Add all of the jobs from the system-wide cron directory.
cat "${CRONDIR}"/* | clean_cron_lines >>"${temp}" # */ <not a comment>
# Add each user's crontab (if it exists). Insert the user's name between the
# five time fields and the command.
while read user ; do
crontab -l -u "${user}" 2>/dev/null |
clean_cron_lines |
sed --regexp-extended "s/^((\S+ +){5})(.+)$/\1${user} \3/" >>"${temp}"
done < <(cut --fields=1 --delimiter=: /etc/passwd)
# Output the collected crontab lines. Replace the single spaces between the
# fields with tab characters, sort the lines by hour and minute, insert the
# header line, and format the results as a table.
cat "${temp}" |
sed --regexp-extended "s/^(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(.*)$/\1\t\2\t\3\t\4\t\5\t\6\t\7/" |
sort --numeric-sort --field-separator="${tab}" --key=2,1 |
sed "1i\mi\th\td\tm\tw\tuser\tcommand" |
column -s"${tab}" -t
rm --force "${temp}"
Related Topics
Make Install Error 'Nothing to Be Done'
Splitting a Large Directory into Smaller Ones in Linux
How to Run a Bash Function() in a Remote Host? in Ubuntu
Youcompleteme Can't Find Local Header Files
Bash Script for Executing Commands on Multiple Server
Ssh - Help Understanding Proxy Command
How to Source a Simple Bash Script
How to Make a Cross Compiler Using Gcc
Implementation of Function Execve (Unistd.H)
Vue Npm Run Serve Failed to Load Resource: Net::Err_Content_Length_Mismatch
Suppressing Compile Time Linkage of Shared Libraries
Omnibus or Source - Can't Decide Which One to Use for Gitllab Backup/Restore
Why Am I Getting an "Implicit Declaration of Function 'Ndo_Get_Stats' " Error