I'm new to bash.
I want to convert below alias command form tcsh to bash:
alias buzz 'echo \!$;if (-e ~/.sshelp.txt) grep -i \!$ ~/.sshelp.txt && echo \!$;if (-e ~/.sshelp_qct.txt) grep -i \!$ ~/.sshelp_qct.txt '
I tried below command but it doesn't work. Any suggestions?
alias buzz= 'echo \!$;if (-e ~/.sshelp.txt) grep -i \!$ ~/.sshelp.txt && echo \!$;if (-e ~/.sshelp_qct.txt) grep -i \!$ ~/.sshelp_qct.txt '
Define a function in bash. C shells define aliases because they don't support functions. I think the following is (roughly) equivalent.
buzz () {
echo "$1"
if [ -e ~/.sshelp.txt ]; then
grep -i "$1" ~/.sshelp.txt && echo "$1"
fi
echo "$1"
if [ -e ~/.sshelp_qct.txt ]; then
grep -i "$1" ~/.sshelp_qct.txt
fi
}
Related
At fisrt,I have write the code,and it run well.
# version1
all_num=10
thread_num=5
a=$(date +%H%M%S)
seq 1 ${all_num} | xargs -n 1 -I {} -P ${thread_num} sh -c 'echo abc{}'
b=$(date +%H%M%S)
echo -e "startTime:\t$a"
echo -e "endTime:\t$b"
Now I want to extract code into a funciton,but it was wrong,how to fix it?
get_file(i){
echo "abc"+i
}
all_num=10
thread_num=5
a=$(date +%H%M%S)
seq 1 ${all_num} | xargs -n 1 -I {} -P ${thread_num} sh -c "$(get_file {})"
b=$(date +%H%M%S)
echo -e "startTime:\t$a"
echo -e "endTime:\t$b"
Because /bin/sh isn't guaranteed to have support for either printing text that when evaluates defines your function, or exporting functions through the environment, we need to do this the hard way, just duplicating the text of the function inside the copy of sh started by xargs.
Other questions already exist in this site describing how to accomplish this with bash, which is quite considerably easier. See f/e How can I use xargs to run a function in a command substitution for each match?
#!/bin/sh
all_num=10
thread_num=5
batch_size=1 # but with a larger all_num, turn this up to start fewer copies of sh
a=$(date +%H%M%S) # warning: this is really inefficient
seq 1 ${all_num} | xargs -n "${batch_size}" -P "${thread_num}" sh -c '
get_file() { i=$1; echo "abc ${i}"; }
for arg do
get_file "$arg"
done
' _
b=$(date +%H%M%S)
printf 'startTime:\t%s\n' "$a"
printf 'endTime:\t%s\n' "$b"
Note:
echo -e is not guaranteed to work with /bin/sh. Moreover, for a shell to be truly compliant, echo -e is required to write -e to its output. See Why is printf better than echo? on UNIX & Linux Stack Exchange, and the APPLICATION USAGE section of the POSIX echo specification.
Putting {} in a sh -c '...{}...' position is a Really Bad Idea. Consider the case where you're passed in a filename that contains $(rm -rf ~)'$(rm -rf ~)' -- it can't be safely inserted in an unquoted context, or a double-quoted context, or a single-quoted context, or a heredoc.
Note that seq is also nonstandard and not guaranteed to be present on all POSIX-compliant systems. i=0; while [ "$i" -lt "$all_num" ]; do echo "$i"; i=$((i + 1)); done is an alternative that will work on all POSIX systems.
When I change directory (cd) into one specific directory (which contains a rails application) it changes the PATH variable, removing many directories from PATH including /bin, /usr/bin, and /usr/local/bin, after which I get many bash errors of "command not found" for commands like which, ls, grep, etc. It appears to be only that one directory which causes the problem, when I cd into it or cd from it. I don't see any obvious files in the directory which would be changing the PATH variable in this way. Before I enter the directory, my PATH looks like this:
$ echo $PATH
/usr/local/opt/node#10/bin:/usr/local/opt/postgresql#9.4/bin:/Users/cedric/.rbenv/shims:/Users/cedric/.rbenv/shims:/Users/cedric/.rvm/gems/ruby-2.3.7/bin:/Users/cedric/.rvm/gems/ruby-2.3.7#global/bin:/Users/cedric/.rvm/rubies/ruby-2.3.7/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/cedric/.rvm/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin:/usr/local/bin/AWS_Tools/AutoScaling-1.0.61.6/bin:/usr/local/bin/AWS_Tools/CloudWatch-1.0.20.0/bin:/usr/local/bin/AWS_Tools/AWS-ElasticBeanstalk-CLI-2.6.3/api/:/usr/local/bin/AWS_Tools/AWS-ElasticBeanstalk-CLI-2.6.3/AWSDevTools/:/usr/local/bin/AWS_Tools/AWS-ElasticBeanstalk-CLI-2.6.3/eb/:/usr/local/bin/AWS_Tools/AWS-ElasticBeanstalk-CLI-2.6.3/eb/linux/python2.7/:/usr/local/bin/AWS_Tools/AWS-ElasticBeanstalk-CLI-2.6.3/eb/macosx/python2.7/:/usr/local/bin/AWS_Tools/AWS-ElasticBeanstalk-CLI-2.6.3/eb/macosx/python2.7/eb:/usr/local/mysql/bin:/Users/cedric/.rbenv/bin:/Users/cedric/.rbenv/shims:/usr/local/mysql/bin
After I enter the directory, my PATH looks like this:
cedric#Computer togo [develop] $ cd .
sed: illegal option -- r
usage: sed script [-Ealn] [-i extension] [file ...]
sed [-Ealn] [-i extension] [-e script] ... [-f script_file] ... [file ...]
-bash: cat: command not found
-bash: cat: command not found
-bash: cut: command not found
cedric#Computer togo $ echo $PATH
/Users/cedric/.rvm/gems/ruby-2.3.7#togo/bin:/Users/cedric/.rvm/gems/ruby-2.3.7#global/bin:/Users/cedric/.rvm/rubies/ruby-2.3.7/bin:/Users/cedric/.rvm/bin:
-bash: cut: command not found
cedric#Computer togo $
This wasn't a problem before today. Any thoughts on what could be causing this?
Thank you
RESPONSES TO COMMENTS:
$ echo "$PROMPT_COMMAND"
update_terminal_cwd;
$ type update_terminal_cwd
update_terminal_cwd is a function
update_terminal_cwd ()
{
local SEARCH=' ';
local REPLACE='%20';
local PWD_URL="file://$HOSTNAME${PWD//$SEARCH/$REPLACE}";
printf '\e]7;%s\a' "$PWD_URL"
}
(seems like that's just replacing "%20" for " " whatever PWD_URL is.)
$ type cd returns
cd is a function
cd ()
{
__zsh_like_cd cd "$#"
}
and
$ type __zsh_like_cd
__zsh_like_cd is a function
__zsh_like_cd ()
{
\typeset __zsh_like_cd_hook;
if builtin "$#"; then
for __zsh_like_cd_hook in chpwd "${chpwd_functions[#]}";
do
if \typeset -f "$__zsh_like_cd_hook" > /dev/null 2>&1; then
"$__zsh_like_cd_hook" || break;
fi;
done;
true;
else
return $?;
fi
}
In the output of set I find:
chpwd_functions=([0]="__rvm_cd_functions_set")
...
__rvm_after_cd ()
{
\typeset rvm_hook;
rvm_hook="after_cd";
if [[ -n "${rvm_scripts_path:-}" || -n "${rvm_path:-}" ]]; then
source "${rvm_scripts_path:-$rvm_path/scripts}/hook";
fi
}
...
__rvm_cd_functions_set ()
{
__rvm_do_with_env_before;
if [[ -n "${rvm_current_rvmrc:-""}" && "$OLDPWD" == "$PWD" ]]; then
rvm_current_rvmrc="";
fi;
__rvm_project_rvmrc 1>&2 || true;
__rvm_after_cd || true;
__rvm_do_with_env_after;
return 0
}
There was a lot of output for set | grep sed (48 lines) so I searched for such output with PATH:
$ set | grep sed | grep -i path
\command \cat "$environment_file_path" | __rvm_grep -Eo "[^ ]+=[^;]+" | __rvm_sed -e 's/\$PATH/'"${PATH//\//\\/}"'/' -e 's/\${PATH}/'"${PATH//\//\\/}"'/';
rvm_silence_logging=1 "$rvm_scripts_path/gemsets" list strings | __rvm_sed "s/ (default)//; s/^/$current_ruby${rvm_gemset_separator:-#}/ ; s/#default// ;"
__rvm_sed -e 's/#.*$//g' -e 's#\[##g' -e 's#\]##g' < "$rvm_path/config/known" | sort -r | uniq;
<log>Usually this is caused by shell initialization files. Search for <code>PATH=...</code> entries.
PATH="$(\sed -E -e 's#/+#/#g' -e 's#/:#:#' <<<$PATH)";
PATH="$(\sed -r -e 's#/+#/#g' -e 's#/:#:#' <<<$PATH)";
__rvm_sed_i "$__rvmrc_warning_path" -e "\#^${1}\$# d" -e '/^$/ d';
__rvm_sed_i "$__rvmrc_warning_path" -e "\#/${__rvmrc_type}\$# d" -e '\#^$# d';
__rvm_sed_i "$__rvmrc_warning_path" -e "\#^${1}\$# d" -e '\#^$# d';
Also, searching for places where PATH is set, it seems like they are all including the original value of PATH in the new value:
$ set | grep "\<PATH *="
PATH=/usr/local/opt/node#10/bin:/usr/local/opt/postgresql#9.4/bin:/Users/cedric/.rbenv/shims:/Users/cedric/.rbenv/shims:/Users/cedric/.rvm/gems/ruby-2.3.7/bin:/Users/cedric/.rvm/gems/ruby-2.3.7#global/bin:/Users/cedric/.rvm/rubies/ruby-2.3.7/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/cedric/.rvm/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin:/usr/local/bin/AWS_Tools/AutoScaling-1.0.61.6/bin:/usr/local/bin/AWS_Tools/CloudWatch-1.0.20.0/bin:/usr/local/bin/AWS_Tools/AWS-ElasticBeanstalk-CLI-2.6.3/api/:/usr/local/bin/AWS_Tools/AWS-ElasticBeanstalk-CLI-2.6.3/AWSDevTools/:/usr/local/bin/AWS_Tools/AWS-ElasticBeanstalk-CLI-2.6.3/eb/:/usr/local/bin/AWS_Tools/AWS-ElasticBeanstalk-CLI-2.6.3/eb/linux/python2.7/:/usr/local/bin/AWS_Tools/AWS-ElasticBeanstalk-CLI-2.6.3/eb/macosx/python2.7/:/usr/local/bin/AWS_Tools/AWS-ElasticBeanstalk-CLI-2.6.3/eb/macosx/python2.7/eb:/usr/local/mysql/bin:/Users/cedric/.rbenv/bin:/Users/cedric/.rbenv/shims:/usr/local/mysql/bin
PATH="$2:$PATH"
PATH="$PATH:$2"
PATH="${rvm_user_path_prefix}:$PATH";
PATH="$PATH:${rvm_bin_path}";
PATH="${rvm_bin_path}:$PATH";
printf "%b" "export PATH=\"${__path}:\$PATH\"\n" > "$file_name";
PATH="${_new_path[*]}:$PATH";
env | __rvm_grep -E '^GEM_HOME=|^GEM_PATH=|^PATH=';
<log>Usually this is caused by shell initialization files. Search for <code>PATH=...</code> entries.
PATH="${save_PATH}";
PATH="$(\sed -E -e 's#/+#/#g' -e 's#/:#:#' <<<$PATH)";
PATH="$(\sed -r -e 's#/+#/#g' -e 's#/:#:#' <<<$PATH)";
command_to_run=(/usr/bin/env PATH="${PATH}${missing_paths}" "${command_to_run[#]}");
PATH="${_OLD_VIRTUAL_PATH}";
PATH="${__path_prefix:-}${__path_prefix:+:}$__save_PATH${__path_suffix:+:}${__path_suffix:-}";
Does any of the above raise red flags as a possible culprit? Should I be checking for something more specific?
RESPONSE TO #Roadowl (in that directory):
$ /bin/ls -la -- -*
ls: -*: No such file or directory
chruby can do this, using preexec_function in zsh and trap in bash. My answer from https://github.com/postmodern/chruby/blob/master/share/chruby/auto.sh:
You're probably sourcing https://github.com/postmodern/chruby/blob/master/share/chruby/auto.sh
which includes a trap command in bash and a preexec_function command in zsh to run chruby_auto when you change directory.
What chruby_auto does is look for the .ruby_version file you have and set ruby from that file by changing path variables.
I have a function that generates a random file name
#generate random file names
get_rand_filename() {
if [ "$ASCIIONLY" == "1" ]; then
for ((i=0; i<$((MINFILENAMELEN+RANDOM%MAXFILENAMELEN)); i++)) {
printf \\$(printf '%03o' ${AARR[RANDOM%aarrcount]});
}
else
# no need to escape double quotes for filename
cat /dev/urandom | tr -dc '[ -~]' | tr -d '[$></~:`\\]' | head -c$((MINFILENAMELEN+RANDOM%MAXFILENAMELEN)) #| sed 's/\(["]\)/\\\1/g'
fi
printf "%s" $FILEEXT
}
export -f get_rand_filename
When I call it from within another function
cf(){
fD=$1
echo "the target dir recieved is " $fD
CFILE="$(get_rand_filename)"
echo "the file name is "$CFILE
}
export -f cf
when I call
echo "$targetdir" | xargs -0 sh -c 'cf $1' sh
I only get the FILEXT (no random file name)
when I call
cf "$targetdir"
I get a valid result
I need to be able to handle spaces in the $targetdir and file name string.
echo "$targetdir" | xargs -0 sh -c 'cf $1' sh
You should invoke bash rather than sh. Function exporting is a bash feature.
$ foo() { echo bar; }
$ export -f foo
$ sh -c 'foo'
sh: 1: foo: not found
$ bash -c 'foo'
bar
Also, get rid of the -0 option since the input isn't NUL-separated. Use -d'\n' instead. And quote "$1" for robustness.
echo "$targetdir" | xargs -d'\n' bash -c 'cf "$1"' bash
Actually, you could use -0 if you change the input format.
printf '%s\0' "$targetdir" | xargs -0 bash -c 'cf "$1"' bash
For what it's worth, mktemp creates random temporary files, and does it safely. It makes sure the file doesn't already exist and then creates it to prevent anybody else from snatching up the name in the split second between the name being generated and it being returned to the caller.
#!/bin/bash
set_bash_profile()
{
local bash_profile="$HOME/.profile"
if [[ -w $bash_profile ]]; then
if (grep 'MY_VAR' $bash_profile 2>&1); then
sed -i '/MY_VAR/d' $bash_profile
fi
echo "export MY_VAR=foo" >>$bash_profile
fi
}
set_bash_profile
Here is the first run:
bash-4.1$ ./set_bash.sh
No output --which is great! And cat shows export MY_VAR=foo was appended to the file. But when executing a second time, I want sed to silently edit $bash_profile without outputting the matching string, like it does here:
bash-4.1$ ./set_bash.sh
export MY_VAR=foo
You get the output from grep on grep 'MY_VAR' $bash_profile 2>&1. grep outputs the matched line in your profile:
export MY_VAR=foo
on stdout. The 2>&1 only forwards stderr to stdout. It's good to use -q option with grep. Also the subshell (...) around the grep is not needed. Try this:
#!/bin/bash
set_bash_profile()
{
local bash_profile="$HOME/.profile"
if [ -w $bash_profile ]; then
if grep -q 'MY_VAR' $bash_profile; then
sed -i '/MY_VAR/d' $bash_profile
fi
echo "export MY_VAR=foo" >>$bash_profile
fi
}
set_bash_profile
I have used the below content to fetch some values .
But the grep in the code is not showing any results.
#!/bin/bash
file=test.txt
while IFS= read -r cmd;
do
check_address=`grep -c $cmd music.cpp`
if [ $check_address -ge 1 ]; then
echo
else
grep -i -n "$cmd" music.cpp
echo $cmd found
fi
done < "$file"
Note : there are no carriage return in my text file or .sh file.
i checked using
bash -x check.sh
It is just showing
+grep -i -n "$cmd" music.cpp