file-list with env variable - shell

In linux, I have a file-list named file_list.txt, where the paths in that list include also an env variable (for this example, the file listed in that file-list is $HOME/myfile).
> cat file_list.txt
$HOME/myfile
> ls `cat file_list.txt`
ls: $HOME/myfile: No such file or directory
> ls $HOME/myfile
/home/user/myfile
Why is that? How can I run operations (such as ls, less, vim etc) on the files listed in the file-list?

If you want to expand the variables you will need something like:
$ sh -c "ls `cat file_list.txt`"
In this case, the commands are read from string and therefore extending variables if any.
$ eval "ls `cat file_list.txt`"
Just in case check also this question: Why should eval be avoided in Bash, and what should I use instead?

Related

csh doesn't recognize command with command line options beginning with --

I have an rsync command in my csh script like this:
#! /bin/csh -f
set source_dir = "blahDir/blahBlahDir"
set dest_dir = "foo/anotherFoo"
rsync -av --exclude=*.csv ${source_dir} ${dest_dir}
When I run this I get the following error:
rsync: No match.
If I remove the --exclude option it works. I wrote the equivalent script in bash and that works as expected
#/bin/bash -f
source_dir="blahDir/blahBlahDir"
dest_dir="foo/anotherFoo"
rsync -av --exclude=*.csv ${source_dir} ${dest_dir}
The problem is that this has to be done in csh only. Any ideas on how I can get his to work?
It's because csh is trying to expand --exclude=*.csv into a filename, and complaining because it cannot find a file matching that pattern.
You can get around this by enclosing the option in quotes:
rsynv -rv '--exclude=*.csv' ...
or escaping the asterisk:
rsynv -rv --exclude=\*.csv ...
This is a consequence of the way csh and bash differ in their default treatment of arguments with wildcards that don't match a file. csh will complain while bash will simply leave it alone.
You may think bash has chosen the better way but that's not necessarily so, as shown in the following transcript where you have a file matching the argument:
pax> touch -- '--file=xyzzy.csv' ; ls -- *.csv
--file=xyzzy.csv
pax> echo --file=*.csv
--file=xyzzy.csv
You can see there that the bash shell expands the argument rather than giving it to the program as is. Both sides have their pros and cons.

Get current directory and concatenate a path

This is a shell script (.sh file). I need to create an absolute path based on the current directory. I know about pwd, but how do I concatenate it with another string? Here is an example of what I am trying to do:
"$pwd/some/path"
Sounds like you want:
path="$(pwd)/some/path"
The $( opens a subshell (and the ) closes it) where the contents are executed as a script so any outputs are put in that location in the string.
More useful often is getting the directory of the script that is running:
dot="$(cd "$(dirname "$0")"; pwd)"
path="$dot/some/path"
That's more useful because it resolves to the same path no matter where you are when you run the script:
> pwd
~
> ./my_project/my_script.sh
~/my_project/some/path
rather than:
> pwd
~
> ./my_project/my_script.sh
~/some/path
> cd my_project
> pwd
~/my_project
> ./my_script.sh
~/my_project/some/path
More complex but if you need the directory of the current script running if it has been executed through a symlink (common when installing scripts through homebrew for example) then you need to parse and follow the symlink:
if [[ "$OSTYPE" == *darwin* ]]; then
READLINK_CMD='greadlink'
else
READLINK_CMD='readlink'
fi
dot="$(cd "$(dirname "$([ -L "$0" ] && $READLINK_CMD -f "$0" || echo "$0")")"; pwd)"
More complex and more requirements for it to work (e.g. having a gnu compatible readlink installed) so I tend not to use it as much. Only when I'm certain I need it, like installing a command through homebrew.
Using the shell builtin pwd in a command substitution ($(...)) is an option, but not necessary, because all POSIX-compatible shells define the special $PWD shell variable that contains the current directory as an absolute path, as mandated by POSIX.
Thus, using $PWD is both simpler and more efficient than $(pwd):
"$PWD/some/path" # alternatively, for visual clarity: "${PWD}/some/path"
However, if you wanted to resolve symlinks in the directory path, you DO need pwd, with its -P option:
"$(pwd -P)/some/path"
Note that POSIX mandates that $PWD contain an absolute pathname with symlinks resolved.
In practice, however, NO major POSIX-like shell (bash, dash, ksh, zsh) does that - they all retain symbolic link components. Thus, the (POSIX-compliant) pwd -P is needed to resolve them.
Note that all said POSIX-like shells implement pwd as a builtin that supports -P.
Michael Allen's helpful answer points out that it's common to want to know the directory of where the running script is located.
The challenge is that the script file itself may be a symlink, so determining the true directory of origin is non-trivial, especially when portability is a must.
This answer (of mine) shows a solution.
wd=`pwd`
new_path="$wd/some/path"
with "dirname $0" you can get dynamin path upto current run scipt.
for example : your file is locateted in shell folder file name is xyz and there are anthor file abc to include in xyz file.
so put in xyz file LIke:
php "`dirname $0`"/abc.php

Alias with > into /dev/clipboard not working

In my cygwin's .bashrc I have the following two aliases:
alias dospath='cygpath -w `pwd`'
alias dospathcp='dospath > /dev/clipboard'
The first one is supposed to print the dos (or windows) path of the directory in which it is executed. This one works as expected.
The second alias is then supposed to redirect the output of dospath into /dev/clipboard so that I can paste it in windows applications. This one does not work. When I type dospathcp in bash, it just empties /dev/clipboard (and the clipbaord itself).
Try as follows:
alias dospath='cygpath -w $PWD'
alias dospathcp='dospath > /dev/clipboard'
This produces following output in my CYGWIN_NT-6.1-WOW64 CC 1.7.25(0.270/5/3) 2013-08-31 20:39 i686 Cygwin
$ alias dospath='cygpath -w $PWD'
$ cd /home/somedir
$ dospath
W:\cygwin\home\somedir
$ cd /home/anotherdir
$ dospath
W:\cygwin\home\anotherdir
$ alias dospathcp='dospath > /dev/clipboard'
$ cd /home/somedir
$ dospathcp
$ cat /dev/clipboard
W:\cygwin\home\somedir
$ cd /home/anotherdir
$ dospathcp
$ cat /dev/clipboard
W:\cygwin\home\anotherdir
See http://ss64.com/bash/alias.html
The first word of the replacement text is tested for aliases, but a
word that is identical to an alias being expanded is not expanded a
second time. This means that one may alias ls to "ls -F", for
instance, and Bash does not try to recursively expand the replacement
text.

Bash command as variable

I am trying to store the start of a sed command inside a variable like this:
sedcmd="sed -i '' "
Later I then execute a command like so:
$sedcmd s/$orig_pkg/$package_name/g $f
And it doesn't work. Running the script with bash -x, I can see that it is being expanded like:
sed -i ''\'''\'''
What is the correct way to express this?
Define a shell function:
mysed () {
sed -i "" "$#"
}
and call it like this:
$ mysed s/$orig_pkg/$package_name/g $f
It works when the command is only one word long:
$ LS=ls
$ $LS
But in your case, the shell is trying the execute the program sed -i '', which does not exist.
The workaround is to use $SHELL -c:
$ $SHELL -c "$LS"
total 0
(Instead of $SHELL, you could also say bash, but that's not entirely reliable when there are multiple Bash installations, the shell isn't actually Bash, etc.)
However, in most cases, I'd actually use a shell function:
sedcmd () {
sed -i '' "$#"
}
Why not use an alias or a function? You can do alias as
alias sedcmd="sed -i '' "
Not exactly sure what you're trying to do, but my suggestion is:
sedcmd="sed -i "
$sedcmd s/$orig_pkg/$package_name/g $f
You must set variables orig_pkg package_name and f in your shell first.
If you're replacing variable names in a file, try:
$sedcmd s/\$orig_pkg/\$package_name/g $f
Still f must be set to the file name you're working on.
This is the right way for do that
alias sedcmd="sed -i ''"
Obviously remember that when you close your bash, this alias will be gone.
If you want to make it "permanent", you have to add it to your .bashrc home file (if you want to make this only for a single user) or .bashrc global file, if you want to make it available for all users

How to find out where alias (in the bash sense) is defined when running Terminal in Mac OS X

How can I find out where an alias is defined on my system? I am referring to the kind of alias that is used within a Terminal session launched from Mac OS X (10.6.3).
For example, if I enter the alias command with no parameters at a Terminal command prompt, I get a list of aliases that I have set, for example:
alias mysql='/usr/local/mysql/bin/mysql'
However, I have searched all over my system using Spotlight and mdfind in various startup files and so far can not find where this alias has been defined. ( I did it a long time ago and didn't write down where I assigned the alias).
For OSX, this 2-step sequence worked well for me, in locating an alias I'd created long ago and couldn't locate in expected place (~/.zshrc).
cweekly:~ $ which la
la: aliased to ls -lAh
cweekly:~$ grep -r ' ls -lAh' ~
/Users/cweekly//.oh-my-zsh/lib/aliases.zsh:alias la='ls -lAh'
Aha! "Hiding" in ~/.oh-my-zsh/lib/aliases.zsh. I had poked around a bit in .oh-my-zsh but had overlooked lib/aliases.zsh.
you can just simply type in alias on the command prompt to see what aliases you have. Otherwise, you can do a find on the most common places where aliases are defined, eg
grep -RHi "alias" /etc /root
First use the following commands
List all functions
functions
List all aliases
alias
If you aren't finding the alias or function consider a more aggressive searching method
Bash version
bash -ixlc : 2>&1 | grep thingToSearchHere
Zsh version
zsh -ixc : 2>&1 | grep thingToSearchHere
Brief Explanation of Options
-i Force shell to be interactive.
-c Take the first argument as a command to execute
-x -- equivalent to --xtrace
-l Make bash act as if invoked as a login shell
Also in future these are the standard bash config files
/etc/profile
~/.bash_profile or ~/.bash_login or ~/.profile
~/.bash_logout
~/.bashrc
More info: http://www.heimhardt.com/htdocs/bashrcs.html
A bit late to the party, but I was having the same problem (trying to find where the "l." command was aliased in RHEL6), and ended up in a place not mentioned in the previous answers. It may not be found in all bash implementations, but if the /etc/profile.d/ directory exists, try grepping there for unexplained aliases. That's where I found:
[user#server ~]$ grep l\\. /etc/profile.d/*
/etc/profile.d/colorls.csh:alias l. 'ls -d .*'
/etc/profile.d/colorls.csh:alias l. 'ls -d .* --color=auto'
/etc/profile.d/colorls.sh: alias l.='ls -d .*' 2>/dev/null
/etc/profile.d/colorls.sh:alias l.='ls -d .* --color=auto' 2>/dev/null
The directory isn't mentioned in the bash manpage, and isn't properly part of where bash searches for profile/startup info, but in the case of RHEL you can see the calling code within /etc/profile:
for i in /etc/profile.d/*.sh ; do
if [ -r "$i" ]; then
if [ "${-#*i}" != "$-" ]; then
. "$i"
else
. "$i" >/dev/null 2>&1
fi
fi
done
Please do check custom installations/addons/plugins you have added, in addition to the .zshrc/.bashrc/.profile etc files
So for me: it was git aliased to 'g'.
$ which g
g: aliased to git
Then I ran the following command to list all aliases
$ alias
I found a whole lot of git related aliases that I knew I had not manually added.
This got me thinking about packages or configurations I had installed. And so went to the
.oh-my-zsh
directory. Here I ran the following command:
$ grep -r 'git' . |grep -i alias
And lo and behold, I found my alias in :
./plugins/git/git.plugin.zsh
I found the answer ( I had been staring at the correct file but missed the obvious ).
The aliases in my case are defined in the file ~/.bash_profile
Somehow this eluded me.
For more complex setups (e.g. when you're using a shell script framework like bash-it, oh-my-zsh or the likes) it's often useful to add 'alias mysql' at key positions in your scripts. This will help you figure out exactly when the alias is added.
e.g.:
echo "before sourcing .bash-it:"
alias mysql
. $HOME/.bash-it/bash-it.sh
echo "after sourcing bash:"
alias mysql
I think that maybe this is similar to what ghostdog74 meant however their command didn't work for me.
I would try something like this:
for i in `find . -type f`; do # find all files in/under current dir
echo "========"
echo $i # print file name
cat $i | grep "alias" # find if it has alias and if it does print the line containing it
done
If you wanted to be really fancy you could even add an if [[ grep -c "alias" ]] then <print file name>
The only reliable way of finding where the alias could have been defined is by analyzing the list of files opened by bash using dtruss.
If
$ csrutil status
System Integrity Protection status: enabled.
you won't be able to open bash and you may need a copy.
$ cp /bin/bash mybash
$ $ codesign --remove-signature mybash
and then use
sudo dtruss -t open ./mybash -ic exit 2>&1 | awk -F'"' '/^open/ {print substr($2, 0, length($2)-2)}'
to list all the files where the alias could have been defined, like
/dev/dtracehelper
/dev/tty
/usr/share/locale/en_CA.UTF-8/LC_MESSAGES/BASH.mo
/usr/share/locale/en_CA.utf8/LC_MESSAGES/BASH.mo
/usr/share/locale/en_CA/LC_MESSAGES/BASH.mo
/usr/share/locale/en.UTF-8/LC_MESSAGES/BASH.mo
/usr/share/locale/en.utf8/LC_MESSAGES/BASH.mo
/usr/share/locale/en/LC_MESSAGES/BASH.mo
/Users/user/.bashrc
/Users/user/.bash_aliases
/Users/user/.bash_history
...
Try: alias | grep name_of_alias
Ex.: alias | grep mysql
or, as already mentioned above
which name_of_alias
In my case, I use Oh My Zsh, so I put aliases definition in ~/.zshrc file.

Resources