Tag Info

Hot answers tagged

12

It's possible to use signals to communicate between the foreground and background shells: #!/bin/bash # global variable for foreground shell boolean=false # register a signal handler for SIGUSR1 trap handler USR1 # the handler sets the global variable handler() { boolean=true; } echo "before: $boolean" # Here, "$$" is the pid of the foreground shell { ...


8

The & character makes a background process. A background process is executed asynchronously in a subshell. Variables can be passed from a parent shell to sub shell, not the other way around. However, you can do a workaround if you are really in need of the value set in the child shell: boolean=$(mktemp) && echo "false" >$boolean { sleep 5 ...


7

I suggest to hire grep for this job: $ OPTS="\"-name user -age 20 -where Asia -eats Brains\"" $ grep -Po -- '-where \K\w*' <<< "$OPTS" Asia Explanation: -P: perl compatible regular expression -o: show only matching parts \K: drop everything before that point \w*: match word constituent (synonym for [_[:alnum:]]) To add " to the list of ...


7

POSIXly: after_first_where=${opts#*-where } word_after_where=${after_first_where%% *} Or to allow any number of blanks between words: after_first_where=${opts#*-where} word_after_where=${after_first_where#"${after_first_where%%[![:blank:]]*}"} word_after_where=${word_after_where%%[[:blank:]]*} Or you could do: unset IFS; set -f # split on blanks, no ...


6

find will set its return code to non-zero if it saw an error. So you can do: if ! find ... then echo had an error >&2 fi | while ... (I'm not sure what you want to do with the find output). To collect all the error messages from find on stderr (file descriptor 2) you can redirect 2 to a file. Eg: if ! find ... 2>/tmp/errors then ...


5

The snippet you provide is out of context, so it's difficult to say what it means in the larger scheme of what you are doing, but: set JUL = $today:e Creates a variable called JUL to the contents of the variable $today, using a tcsh or csh modifier (:e) to remove everything but the extension of $today. set CAL = $today:r Creates a variable called CAL ...


4

You can use '@', for example: $ files=( /tmp/a "/tmp/a file from windows" /tmp/myfile ) $ cat "${files[@]}" > newfile The '@' expands the entire contents of the array. It is similar to *except it will treat each element individuals whereas * will combine all elements as one.


4

You indicate that you said If.  bash keywords are case-sensitive; you must use if (lower case).


4

You mistakenly assume that the boolean you set to true in the second line is the same boolean that you test for in the until statement. That is not the case, you start new process, with a new shell in the background and boolean (the one you test for), never gets assigned.


4

Many tools can be handy: -n of grep is exactly what you are looking for. grep -n 'bla' file alternatively awk: awk '/bla/{print NR":"$0}' file alternatively perl: perl -ne 'print $.,":",$_ if /bla/' file alternatively sed: sed '/bla/!d;=' file |sed 'N;s/\n/:/'


4

A little edit in your script: #!/bin/bash opts="OPTS=\"-name user -age 20 -where Asia -eats Brains\"" echo $opts ok="0" for word in $opts; do if [ "$ok" = "1" ] ; then echo $word break fi if [ "$word" = "-where" ] ; then ok="1" fi done


4

Try running the script as a script instead of sourcing it: $ bash <scriptname>


4

I'm not sure if I understand your question properly, but I believe you want to align the columns. If that is the case then the command column is handy: column -s, -t file Output: Thu Aug 27 2015 7:56:29 AM PoolName Total GB Used GB Available GB Percent Full Oracle-RAID10 6432.539 6179.295 253.244 ...


3

For the third version, you want "$*" not "$@". Explanation To illustrate, let's set some positional arguments: $ set -- arg1 arg2 arg3 Now, let's read them out with your echo formulation: $ printf "%s\n" "$(echo $@)" arg1 arg2 arg3 Let's see what "$@" does with them: $ printf "%s\n" "$@" arg1 arg2 arg3 The difference is that "$@" expands to three ...


3

Rather than roll your own and have to cope with everything that can go wrong (host not responding, host stopping responding in the middle, user pressing Ctrl+C, error reporting, …), use one of the many existing tools to run a command on many machines over SSH. mussh -t 4 -H <(printf '%s\n' "${HOSTS[@]}") -c 'uname -a' pssh -t 4 -h <(printf '%s\n' ...


3

uniq is the correct tool for that: uniq -D -f2 file Where: -D prints all dublicates -f2 to avoid to compare the first 2 fields Edit: If the fields 7 and above are not to be compared, you need awk: awk 'n=x[$3,$4,$5,$6]{print n"\n"$0;} {x[$3,$4,$5,$6]=$0;}' file The array item x[] (columns 3-6) is checked. If it's already set run the part in {...} ...


3

Here's a summary of some of the drawbacks of: cat $file | cmd over < $file cmd First, a note: there are (intentionally for the purpose of the discussion) missing double quotes around $file above. In the case of cat, that's always a problem except for zsh; in the case of the redirection, that's only a problem for bash or for some other shells only ...


3

Bash version 4 introduced built-in case-modification operators ^ and , operators, making it possible to avoid external programs like awk for such simple string manipulations if you have a recent version of the bash shell. In particular, if name=$(hostname) and path="path/to/" then "${path}${name^}" should concatenate the strings, with the first ...


2

Assuming: hour=09 Just use that: grep "\.$hour" file With the single quotes in your example, the variable is not interpreted as variable. Therefore the pattern searches for $hour. Also the dot has to be escaped, else it would match any character.


2

One approach that would work is just appending to the end of the bashrc rather than syncing it. echo "PATH=\$PATH:~/bin" >> ~/.bashrc This will add ~/bin onto the PATH variable. In order to get this on a remote host you just need to call ssh first. You can use a for loop if you have lots of hosts. for host in host1 host2 host3;do ssh ...


2

Bash globs Don't use regex. Use globs (assuming you are using bash). ls l??* Explanation ? stands for a single character. * stands for zero or more characters. Regex If you really wanted to use regex, you could use ls | grep "^l...*" Explanation . stands for a single character. .* stands for zero or more characters.


2

Use this: c=132 for f in *; do mv -v "$f" "enum-$(printf '%0*d' 5 $c)" c=$(($c+1)) done The c=<your_starting_number>; I assumed 132 as in your question. Then the for loop runs trough all the files in the current directory. For every file the mv command is called. the printf utility prints the new filename with leading zeros. And finally the ...


2

Consider a simpler example to see the difference: $ set "a b" c "d e" $ printf "%s\n" "$@" a b c d e The preceding is what you should use; it's simple, easy to understand, and correct. $ printf "%s\n" "$(echo $@)" a b c d e Here, $@ first expands unquoted (the quotes surrounding the command substitution are separate and not yet applied), so it's ...


2

A typical way to do this is to use the trap command to tell the shell script to ignore SIGINT (generated by Control-C), and then to re-enable SIGINT in a subshell just before your command is run. trap "" INT HOSTS=(MACHINE1 MACHINE2 MACHINE3 MACHINE4 MACHINE5) for i in "${HOSTS[@]}" do echo "$i" (trap - INT; ssh -q "$i" "uname -a") done


2

You can try parsing your program's output with sed and executing the commands: $(./YOUR_PROGRAM | sed s/^.*==/rm/ | sed s/\ \(.*//) will execute (from your example) rm new_GS_calculation/selected/POSCAR_0011 rm new_GS_calculation/selected/POSCAR_0022 rm new_GS_calculation/selected/POSCAR_0027 rm new_GS_calculation/selected/POSCAR_0027 rm ...


2

ps -fo user | sort | uniq -c is worth a try. The command ps -eo user=|sort|uniq -c will list process counts by user. ps -eo user=|sort|uniq -c 2 avahi 1 kernoops 1 messagebus 1 nobody 231 root 1 statd 5 steve 1 syslog If flipping the column order to read is required, pipe it through awk '{ print $2 " " $1 ...


2

You can try ps aux | awk 'NR>1{tot[$1]++;} END{for(id in tot)printf "%s %s\n",id,tot[id]}'


2

Line 4 of parent.sh, you wrote sh /child.sh & $f. The ampersand must be put at the end of the command like that: sh /child.sh $f &. In your case, you are trying to run sh /child.sh in background, and then you are executing $f in foreground, which will lead to a permission denied as I can assume that your files /vol4/commit/file[1-9] are not ...


1

A command like xyz=abc def ghi jkl means to run the def program with arguments ghi and jkl, and with environment variable xyz set to abc.  To set HOSTS to the string MACHINE1 MACHINE 2 you would need to say HOSTS="MACHINE1 MACHINE 2" (although I assume that you don't want to have a space between the second MACHINE and the 2.)  You could probably get ...


1

As @StéphaneChazelas mentions, you can use pgrep - from the man page: The pgrep command searches the process table on the running system and prints the process IDs of all processes that match the criteria given on the command line. SERVICE='Google Chrome' if pgrep -xq -- "${SERVICE}"; then echo running else echo not running fi



Only top voted, non community-wiki answers of a minimum length are eligible