I want to use "dtrace" to track file tranfer in OSX 10.8 , like when command "mv /folder1/file1 /folder2" is run .
I know there're probes like create/link/unlink/rename/chdir can be used in the form of
dtrace -n 'syscall::create:entry { printf("%s %s", execname, copyinstr(arg0)); }'
but how to trace this "mv" command ?
rename is the function you are after:
dtrace -n 'syscall::rename:entry { printf("mv %s %s\n",copyinstr(arg0),copyinstr(arg1)); }'
(Add sudo infront if required)
Related
I have a function that executes system calls and writes the output into a QTextEdit.
string SystemCallFactory::runSysCallWithoutButton(unique_ptr<SystemCall> sysCall)
{
cout << "Running " << sysCall->getCommand() << endl;
textEdit->setText("");
textEdit->repaint();
QProcess process;
process.start(QString::fromStdString(sysCall->getCommand()));
process.waitForFinished();
QString output(process.readAllStandardOutput());
textEdit->append(output);
textEdit->repaint();
return output.toStdString();
}
The problem is that this works when getCommand() is a real command, e.g. ls /etc but does not work correctly when it refers to a shellscript. In my calls, the call that does not work looks like
/home/turtle10000/tilematching.sh /some/folder /some/specific.file
The script gets executed and does what it's supposed to do, but readAllStandardOutput() returns an empty string. When I run it in a terminal, it shows the expected output.
This is the shellscript:
#!/bin/sh -v
WORKSPACE=$1
SVPFILE=$2
cd $WORKSPACE
ls -1 *.all > datalist.0.mb-1
mbset -I datalist.0.mb-1 -PSVPMODE:1 -PSVPFILE:$SVPFILE
mbprocess -I datalist.0.mb-1
ls -1 *p.mb58 > datalist.1.mb-1
mbset -I datalist.1.mb-1 -PSONAROFFSETX:-0.079 -PSONAROFFSETY:0.196 -PSONAROFFSETZ:0.048 -PVRUOFFSETX:-0.4473 -PVRUOFFSETY:0.000 -PVRUOFFSETZ:-0.3395 -PROLLBIAS:0.1 -PPITCHBIAS:1.32
mbprocess -I datalist.1.mb-1
ls -1 *pp.mb58 > datalist.2.mb-1
mblist -I datalist.2.mb-1 -MA -O^X^Y-z -JU > output.xyz
#remove broken lines (error in input files)
sed -ie '/ /d' output.xyz
Edit: as Botje guessed, some of output appears in stderr instead of stdout.
As Botje suggested, I checked if the output went to stderr and it did. For whatever reason, the output of mbset and mbprocess, tools from the mb-system package, goes to stderr.
In this case, I changed the line
QString output(process.readAllStandardOutput());
to
QString output(process.readAllStandardError());
Another option would probably be to channel the stderr output to stdout in the script.
I have been using this little script for months now with success. Today I realize there is one output it cant seem to catch, screen comes up blank with a new prompt:
user#computer ~]$ myscan ipsFile 23
user#computer ~]$
Here is the code
#!/bin/bash
sudo nmap -v -Pn -p T:$2 -reason -i $1 | awk ' {
if (/syn-ack/) {
print "Yes"
c++
}
else if (/no-response|reset|host-unreach/) {
print "No"
c++
}
}
END { print c} '
If I run the nmap against one of the IPs then it returns
Starting Nmap 5.51 ( http://nmap.org ) at 2017-09-26 11:44 CDT
Initiating Parallel DNS resolution of 1 host. at 11:44
Completed Parallel DNS resolution of 1 host. at 11:44, 0.00s elapsed
Initiating Connect Scan at 11:44
Scanning 1.1.1.1 [1 port]
Completed Connect Scan at 11:44, 0.20s elapsed (1 total ports)
Nmap scan report for 1.1.1.1
Host is up, received user-set (0.20s latency).
PORT STATE SERVICE REASON
23/tcp filtered telnet host-unreach
Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.26 seconds
How can I catch the 'host-unreach' portion?
Let's try and debug this. Execute this:
nmap -v -Pn -p T:23 -reason -i ipsFile | awk '{print $0}/syn-ack/{print "Yes";c++}/no-response|reset|host-unreach/{print "No";c++}END {print c}' > out.txt
The only difference here is that the awk script prints $0 (i.e. the output of your nmap calls) to file out.txt. Try to grep your unreach value.
I tried this myself and found that instead of a host-unreach I got a net-unreach. Might be the same thing in your case.
Have you tried piping stderr to stdout like
#!/bin/bash
sudo nmap -v -Pn -p T:$2 -reason -i $1 2>&1 | awk ' {
if (/syn-ack/) {
print "Yes"
c++
}
else if (/no-response|reset|host-unreach/) {
print "No"
c++
}
}
END { print c} '
Background
Original json (test.json): {"rpc-password": "password"}
Expected changed json: {"rpc-password": "somepassword"}
replace_json_str is a function used to replace password with somepassword using sed.
replace_json_str() {
x=$1
sed -i -e 's/\({ "'"$2"'":\)"[^"]*" }/\1"'"$3"'" }/g' $x
}
Unit test: replace_json_str test.json rpc-password somepassword
Issue
After running the above test, I get a file named test.json-e and the contents of the file is the same as before the test was ran, why?
there is a handy command line json tool called jq
cat input.json
{"rpc-password": "password"}
cat update_json.sh
givenkey=$1
givenvalue=$2
inputfile=input.json
outfile=output.json
cat $inputfile | jq . # show input json
jq --arg key1 "$givenkey" --arg val1 "$givenvalue" '.[$key1] = $val1' "$inputfile" > "$outfile"
cat "$outfile" | jq . # render output json
keep in mind jq can handle multiple such key value updates ... execute it
update_json.sh rpc-password somepassword
{
"rpc-password": "password"
}
{
"rpc-password": "somepassword"
}
Depends on which sed you're using.
The command you ran will work as expected with GNU sed.
But BSD sed does not allow for an empty argument to -i, and if you ran the same command, it will use the next argument, -e, as the backup file.
Also, the positioning of the spaces in your pattern don't match your example JSON.
I have a function read_command defined as:
function read_command {
local __newline __lines __input __newstr __tmp i;
exec 3< "$*";
__newline=$'\n';
__lines=();
while IFS= read <&3 -r __line && [ "$__line" != '####' ]; do
echo "$__line";
__lines+=("$__line");
done
while IFS= read <&3 -r __line && [ "$__line" != '####' ]; do
read -e -p "${__line#*:}$PS2" __input;
local ${__line%%:*}="$__input";
done
__command="";
for i in "${__lines[#]}"; do
__tmp=$(echo "${i}");
__command="${__command} ${__newline} ${__tmp}";
done
echo -e "$__command";
}
In the current directory there is a file named "test", with the following
content:
greet ${a:-"Bob"}
greet ${b:-"Jim"}
####
a: name of friend a
b: name of friend b
####
In the terminal, the command executed is
read_command test
With no input, I am expecting the output of the last statement to be:
greet Bob
greet Jim
But what I get is:
greet ${a:-"Bob"}
greet ${b:-"Jim"}
What is wrong here?
Edit: As suggested by David, adding eval works in some cases except the following one.
j=1;i="export DISPLAY=:0 && Xephyr :${j}&";k=$(eval echo "$i");
echo $k
export DISPLAY=:0
I am expecting k to be "export DISPLAY=:0 && Xephyr :1&", what's wrong here?
Edit: I tried with the following
k=$(eval "echo \"$i\"")
This is the link to the script I am working on.
https://gist.github.com/QiangF/565102ba3b6123942b9bf6b897c05f87
During the first while loop, in echo "$__line", you have __line='greet ${a:-"Bob"}'. When you try to print that, Bash won't be expanding ${a:-"Bob"} into Bob. (Even if you remove the quotes around $__line this won't happen.) To get that effect, you need to add eval, as in, e.g., eval echo "$__line". Unfortunately eval comes with its can of worms, you have to start worrying about interactions between quoting levels and such.
I want to be able to write a program that when you type in commands, it will do things like count the amount of times you've used cd. Something similar to this:
[ : ~ $] cd public_html
Congratulations! You've earned the Badge 'cd master!'. Level up!
All my C++ file consists of so far is:
#include <iostream>
int main(int argc, char* argv[]) {
int counter = 0;
for (int i = 1; i < argc; i++) {
std::cout << argv[i] << std::endl;
if (argv[i] == "cd")
std::cout << "Badge earned 'cd master!' +5120 experience points" << std::endl;
}
return 0;
}
As it reflects one attempted solution involving:
#!/bin/sh
bash | tee ./main
and
bind 'RETURN: "echo $(!!) | tee ~/.main \n"'
I've decided to go with
export PROMPT_COMMAND='history | tail -n1'
But that would mean having to parse the output.
What's the easiest way of accomplishing this?
edit
Here's what I've managed to produce:
#!/bin/sh
export COUNTER=0
export MAXWIDTH=10
export TNL=1000
update_prompt() {
export PS1="> "
}
cd() {
COUNTER=$(($COUNTER + 25));
echo +25;
builtin cd $#;
}
help() {
echo "custom commands are: score";
}
score() {
echo $COUNTER"/"$TNL
BAR=$(yes "#" | head -n 10 | tr -d '\n')
OVERLAY=$(yes "%" | head -n 10 | tr -d '\n')
WIDTH=$(echo "$COUNTER*$MAXWIDTH/$TNL" | bc)
FIRST=${BAR:0:WIDTH}
SECOND=${OVERLAY:0:$((MAXWIDTH-WIDTH))}
echo "["$FIRST$SECOND"]"
}
exit() {
echo "Bye bye";
builtin exit $#;
}
export -f update_prompt
export -f cd # export the function
export -f help
export -f score
export -f exit
bash # run subshell with the exported functions
update_prompt
An easy solution is to overwrite the cd command of your shell inside the shell itself. For example, in Bash or ZSH:
cd() {
echo "Congratulations";
builtin cd $#;
}
(This is for example used in projects like autoenv.)
You can do the same for all other commands. You can also call your C++ code from there.
If you want to put that into a script, e.g. name it learn-bash.sh:
cd() { ... }
export -f cd # export the function
bash # run subshell with the exported functions
Another solution, where you have much more power, but which is way more involved: take the source code of Bash (it's C) and extend it (by C or C++). Then you can basically do whatever you want. And you have everything directly there, i.e. the parsed commands, etc.
After every command COMMAND_PROMPT is executed within bash. You could use that with history to see the last command used.
You can read here on how PS1, PS2, PS3 and COMMAND_PROMPT work in bash.
There are a few answers on exactly this question already on SO:
How can I intercept commands that contain a certain string?
bash: how to intercept every command
bash: How to intercept command line and do various actions based on the contents?
I've done something similar a while ago, and here's the solution I've found.
You want to add the following lines to .bashrc:
hook() {
whatever "$#"
}
invoke_hook() {
[ -n "$COMP_LINE" ] && return
[ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return
local command=`history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//g"`;
hook "$command"
}
trap 'invoke_hook' DEBUG
Replace whatever with your C++ program. This will execute your hook before each command, and will pass the original command as the arguments.