I have a shell script like this
Comand 1
gnome-terminal -- ./ a
gnome-terminal -- ./ b
gnome-terminal -- ./ c
Comand 2
Comand 3
How i can make comand 2 ans comand 3 run after all gnome-terminal comands finish?
Thank you
Use --wait
Comand 1
gnome-terminal --wait -- ./ a
gnome-terminal --wait -- ./ b
gnome-terminal --wait -- ./ c
Comand 2
Comand 3
Related
I run a command to batch process image files using resmushit:
find /home/user/image/data -type f -print0 | xargs -n 1 -P 10 -0 resmushit -q 85 --preserve-filename
The command runs successfully and tells me the files were optimized and saved however when I check the files in the folder there is no change.
edit: it looks like the problem might be with resmushit. When I run it on pictures within my working directory it works. i.e
resmushit -q 85 --preserve-filename test.jpg
Is there a way to make xargs or a different command to run the command within each folder recursively?
I ended finding for directories and using a bash file so:
find /home/user/image/data -type d -print0 | xargs -n 1 -P 10 -0 bashscript
and the script is:
#!/bin/sh
cd "$*"
resmushit -q 85 --preserve-filename *
I am writing a perl script, and the objective is to kick start an xterm, follow by setenv, follow by invoke a tool that pre-installed in the system.
Here is my system call command in my perl script
system("xterm","-hold", "-e", "setenv ZI_LIBERTY_IGNORE_CONSTRUCT_FILES $RAW_RF_DIR/lib/lib2v/qcdc_ignore", "setenv HOME_0IN /p/hdk/rtl/cad/x86-64_linux26/mentor/questaCDC/V10.4g_5/linux_x86_64", "modpath -n 1 \$HOME_0IN/bin", "modpath -n 1 \$HOME_0IN/modeltech/bin", "/p/hdk/rtl/cad/x86-64_linux30/mentor/questaCDC/V10.4f_5/linux_x86_64/bin/qcdc -c -licq -do run.tcl");
xterm was able to start, however it stopped when executing the setenv, after that i tried with the new command by replacing the setenv with $ENV
system("xterm","-hold", "-e", "\$ENV{ZI_LIBERTY_IGNORE_CONSTRUCT_FILES} = \"$RAW_RF_DIR/lib/lib2v/qcdc_ignore\"", "setenv HOME_0IN /p/hdk/rtl/cad/x86-64_linux26/mentor/questaCDC/V10.4g_5/linux_x86_64", "modpath -n 1 \$HOME_0IN/bin", "modpath -n 1 \$HOME_0IN/modeltech/bin", "/p/hdk/rtl/cad/x86-64_linux30/mentor/questaCDC/V10.4f_5/linux_x86_64/bin/qcdc -c -licq -do run.tcl");
Here is the error message showing up in the new xterm (same for both approach)
Can't execvp $ENV{ZI_LIBERTY_IGNORE_CONSTRUCT_FILES} = "/nfs/fm/stod/stod4003/w.eew.100/rf_uprev_model_2020ww14p1//subIP/hip/MTLM_SA/RF.1//lib/lib2v/qcdc_ignore": No such file or directory
Please advise that how to make the series of operation works in the new xterm? Thanks!
-Eric-
The program run with -e must be a program, not a shell built-in like setenv. Off the top of my head, I can think of two solutions:
Set the environment variables before starting xterm. They would then be inherited by xterm.
Let the program run by xterm be a shell, and use that shell to set the environment variables and launch the tool. Something like this (untested):
system("xterm", "-e", "/bin/sh", "-c", "FOO=bar; FIE=fum; /run/my/program");
According to the man page I read, the following is the syntax of the -e option:
-e program [ arguments ... ]
It takes a path to a program, and optionally arguments to pass to that program. Specifically, it doesn't take a shell command. (It would be bad to accept a shell command without having the user specify for which shell!) That doesn't preclude one from running a shell command, though. This simply requires launching a shell, as the following does:
xterm -e sh -c shell_cmd
Solution:
my $script = <<'__EOS__';
export ZI_LIBERTY_IGNORE_CONSTRUCT_FILES="$RAW_RF_DIR/lib/lib2v/qcdc_ignore"
export HOME_0IN=/p/hdk/rtl/cad/x86-64_linux26/mentor/questaCDC/V10.4g_5/linux_x86_64
modpath -n 1 "$HOME_0IN/bin"
modpath -n 1 "$HOME_0IN/modeltech/bin"
/p/hdk/rtl/cad/x86-64_linux30/mentor/questaCDC/V10.4f_5/linux_x86_64/bin/qcdc -c -licq -do run.tcl
__EOS__
system("xterm", "-hold", "-e", "sh", "-c", $script)
Since a process normally passes a copy of its env vars to process it creates, you could also write the above as follows:
local $ENV{ZI_LIBERTY_IGNORE_CONSTRUCT_FILES} = "$ENV{RAW_RF_DIR}/lib/lib2v/qcdc_ignore";
local $ENV{HOME_0IN} = "/p/hdk/rtl/cad/x86-64_linux26/mentor/questaCDC/V10.4g_5/linux_x86_64";
my $script = <<'__EOS__';
modpath -n 1 "$HOME_0IN/bin"
modpath -n 1 "$HOME_0IN/modeltech/bin"
/p/hdk/rtl/cad/x86-64_linux30/mentor/questaCDC/V10.4f_5/linux_x86_64/bin/qcdc -c -licq -do run.tcl
__EOS__
system("xterm", "-hold", "-e", "sh", "-c", $script)
You can use csh similarly; I'm simply more familiar with sh.
Following code behaves as expected when running from terminal:
perl -e 'kill -2, $$; warn HERE, $/'
It sends itself SIGINT and dies before reaching "HERE":
~# perl -e 'kill -2, $$; warn HERE, $/'
~# echo $?
130
~#
The problem: same code fails to kill self PID when running from shell script:
~# cat 1.sh
perl -e 'kill -2, $$; warn HERE, $/'
~#
~# sh 1.sh
HERE
~#
~# echo $?
0
~#
On the other hand, replacing perl's kill by a shell's one works OK:
~# cat 2.sh
perl -e 'qx/kill -2 $$/; warn HERE, $/'
~#
~# sh 2.sh
~#
~# echo $?
130
~#
Not really understand what is happening here, please help..
First of all,
kill -2, $$
is better written as
kill 2, -$$
An even better alternative is
kill INT => -$$
These send SIGINT to the specified process group.
Your main question appears to be why the two shells behave differently. This section explains that.
The process group represents an application.
When you launch a program from an interactive shell, it's not part of a larger application, so the shell creates a new process group for the program.
However, processes created by a script (i.e. a non-interactive shell) are part of the same application as the script itself, so the shell doesn't create a new process group for them.
You can visualize this using the following:
sh -i <<< 'perl -e '\''system ps => -o => "pid,ppid,pgrp,comm"'\''' outputs the following:
$ perl -e 'system ps => -o => "pid,ppid,pgrp,comm"'
PID PPID PGRP COMMAND
8179 8171 8179 bash
14654 8179 14654 sh
14655 14654 14655 perl
14656 14655 14655 ps
$ exit
In interactive mode, perl is at the head of perl and ps's program group.
sh <<< 'perl -e '\''system ps => -o => "pid,ppid,pgrp,comm"'\''' outputs the following:
PID PPID PGRP COMMAND
8179 8171 8179 bash
14584 8179 14584 sh
14585 14584 14584 perl
14586 14585 14584 ps
In non-interactive mode, sh is at the head of perl and ps's program group.
Your failures are the result of not sending the signal to the head of the process group (i.e. the application). Had you checked, the error kill reported was ESRCH ("No such process").
ESRCH The pid or process group does not exist. [...]
To kill the current process's process group, replace the improper
kill INT => -$$ # XXX
with
kill INT => -getpgrp() # Kill the application
You can make your perl the head of its own process group by simply calling the following:
setpgrp();
Test:
$ sh <<< 'perl -e '\''system ps => ( -o => "pid,ppid,pgrp,comm" )'\'''
PID PPID PGRP COMMAND
8179 8171 8179 bash
16325 8179 16325 sh
16326 16325 16325 perl
16327 16326 16325 ps
$ sh <<< 'perl -e '\''setpgrp(); system ps => ( -o => "pid,ppid,pgrp,comm" )'\'''
PID PPID PGRP COMMAND
8179 8171 8179 bash
16349 8179 16349 sh
16350 16349 16350 perl
16351 16350 16350 ps
That's not something you normally want to do.
Finally, the Perl code
kill INT => -$pgrp
is equivalent to the following call of the kill command-line utility:
kill -s INT -$pgrp
kill -INT -$pgrp
kill -2 -$pgrp
You were missing - in your qx// program, so it was sending SIGINT to the identified process rather than the identified program group.
From your interactive terminal, the perl process kills the process group of which it is a part. (The shell runs perl in its own process group.) The shell reports this unusual termination in $?:
t0 interactive shell (pid=123, pgrp=123)
|
t1 +------> perl -e (pid=456, pgrp=456, parent=123)
| |
t2 (wait) kill(-2, 456) (in perl, same as kill pgrp 456 w/ SIGINT)
| |
t3 (wait) *SIGINT*
|
t4 report $?
From your shell script, the perl process kills a (likely) non-existent process group and then exits successfully. Your interactive shell makes a new process group in which to run your shell script, and that script then runs perl as a child in the same process group.
t0 shell (pid=123, pgrp=123)
|
t1 +-------> shell:1.sh (pid=456, pgrp=456, parent=123)
| |
t2 (wait) +-------------> perl -e (pid=789, pgrp=456, parent=456)
| | |
t3 (wait) (wait) kill pgrp 789 with SIGINT (error: no such pgrp)
| | |
t4 (wait) (wait) exit success
| |
t5 (wait) exit success
|
t6 report $?
In your backticked (qx//) example, your interactive shell starts a shell process with a new process group. (Not that it matters here, but that process runs perl in its same process group.) Perl then runs as its own child the system kill command, the semantics of which differ from that of the perl kill. This grandchild command sends a SIGINT to the perl PID directly, rather than a SIGINT to a process group. Perl terminates, and that exit code is conveyed as the script's exit code, since it was the last command in the script.
This diagram is a little busier than the previous:
t0 shell (pid=123, pgrp=123)
|
t1 +-------> shell:2.sh (pid=456, pgrp=456, parent=123)
| |
t2 (wait) +----------> perl -e (pid=789, pgrp=456, parent=456)
| | |
t3 (wait) (wait) +---------> /bin/kill SIGINT 789
| | | |
t4 (wait) (wait) *SIGINT* exit success
| |
t5 (wait) return $?
|
t6 report $?
It works fine in this way:
perl -E 'say "kill "INT", $$; warn HERE, $/'
perl -E 'say "kill 2, $$; warn HERE, $/'
kill man page says:
A negative signal name is the same as a negative signal number,
killing process groups instead of processes. For example, kill
'-KILL', $pgrp and kill -9, $pgrp will send SIGKILL to the entire
process group specified. That means you usually want to use positive
not negative signals.
I want to split a large text database (~10 million lines). I can use a command like
$ sed -i -e '4 s/(dB)//' -e '4 s/Best\ unit/Best_Unit/' -e '1,3 d' '/cygdrive/c/ Radio Mobile/Output/TRC_TestProcess/trc_longlands.txt'
$ split -l 1000000 /cygdrive/P/2012/Job_044_DM_Radio_Propogation/Working/FinalPropogation/TRC_Longlands/trc_longlands.txt 1
The first line is to clean the databse and the next is to split it -
but then the output files do not have the field names. How can I incorporate the field names into each dataset and pipe a list which has the original file, new file name and line numbers (from original file) in it. This is so that it can be used in the arcgis model to re-join the final simplified polygon datasets.
ALTERNATIVELY AND MORE USEFULLY -as this needs to go into a arcgis model, a python based solution is best. More details are in https://gis.stackexchange.com/questions/21420/large-point-to-polygon-by-buffer-join-buffer-dissolve-issues#comment29062_21420 and Remove specific lines from a large text file in python
SO GOING WITH A CYGWIN based Python solution as per answer by icyrock.com
we have process_text.sh
cd /cygdrive/P/2012/Job_044_DM_Radio_Propogation/Working/FinalPropogation/TRC_Longlands
mkdir processing
cp trc_longlands.txt processing/trc_longlands.txt
cd txt_processing
sed -i -e '4 s/(dB)//' -e '4 s/Best\ unit/Best_Unit/' -e '1,3 d' 'trc_longlands.txt'
split -l 1000000 trc_longlands.txt trc_longlands_
cat > a
h
1
2
3
4
5
6
7
8
9
^D
split -l 3
split -l 3 a 1
mv 1aa 21aa
for i in 1*; do head -n1 21aa|cat - $i > 2$i; done
for i in 21*; do echo ---- $i; cat $i; done
how can "TRC_Longlands" and the path be replaced with the input filename -in python we have %path%/%name for this.
in the last line is "do echo" necessary?
and this is called by python using
import os
os.system("process_text.bat")
where process_text.bat is basically
bash process_text.sh
I get the following error when run from dos...
Microsoft Windows [Version 6.1.7601] Copyright (c) 2009 Microsoft
Corporation. All rights reserved.
C:\Users\georgec>bash
P:\2012\Job_044_DM_Radio_Propogation\Working\FinalPropogat
ion\TRC_Longlands\process_text.sh 'bash' is not recognized as an
internal or external command, operable program or batch file.
also when I run the bash command from cygwin -I get
georgec#ATGIS25
/cygdrive/P/2012/Job_044_DM_Radio_Propogation/Working/FinalPropogation/TRC_Longlands
$ bash process_text.sh : No such file or directory:
/cygdrive/P/2012/Job_044_DM_Radio_Propogation/Working/FinalPropogation/TRC_Longlands
cp: cannot create regular file `processing/trc_longlands.txt\r': No
such file or directory : No such file or directory: txt_processing :
No such file or directoryds.txt
but the files are created in the root directory.
why is there a "." after the directory name? how can they be given a .txt extension?
If you want to just prepend the first line of the original file to all but the first of the splits, you can do something like:
$ cat > a
h
1
2
3
4
5
6
7
^D
$ split -l 3
$ split -l 3 a 1
$ ls
1aa 1ab 1ac a
$ mv 1aa 21aa
$ for i in 1*; do head -n1 21aa|cat - $i > 2$i; done
$ for i in 21*; do echo ---- $i; cat $i; done
---- 21aa
h
1
2
---- 21ab
h
3
4
5
---- 21ac
h
6
7
Obviously, the first file will have one line less then the middle parts and the last part might be shorter, too, but if that's not a problem, this should work just fine. Of course, if your header has more lines, just change head -n1 to head -nX, X being the number of header lines.
Hope this helps.
perl -E '$i=#{[`zypper lr`]}-2;map{`zypper rr $_`}1..$i'
What would be a good way to write this perl-onliner in bash. ( I would like to remove all repositores with zypper)?
Here's a way to do this:
The first command counts the number of lines produced by zypper lr command.
So, you obtain that by:
COUNT_LINES=`zypper lr|tail +3|wc -l`
The second command merely runs zypper rr [NUMBER] for each number 1 through the counter; so you run the for loop in bash as shown in this SO question:
How do I iterate over a range of numbers in bash?
zypper lr | grep -P "^\d" | cut -d'|' -f 1 | xargs sudo zypper rr
But much easier to simply:
sudo rm -rf /etc/zypp/repos.d/*