This question already has answers here:
Make a Bash alias that takes a parameter?
(24 answers)
Closed 5 years ago.
How do I modify bashrc to include a readme file with the pwd to original source every time I use cp or mv?
It should be something like this:
alias cp="pwd $1 > readme & cp $1 $2"
or
alias cp="pwd $1 > readme | cp $1 $2"
But instead of the path of the source, it gives me the path of the directory I am in.
You can't have aliases with arguments. Since you probably don't have $1 defined, pwd $1 just expands to pwd.
Also, pwd doesn't actualy take any positional arguments. If you want the source to appear in readme, use echo.
Create a function
cp() {
echo $1 > readme
/bin/cp $1 $2
}
Also,
& does not mean AND – it sends processing to background
| does not mean OR – it pipes output of left side to input of right side
Related
This question already has answers here:
How to loop over files in directory and change path and add suffix to filename
(6 answers)
When to wrap quotes around a shell variable?
(5 answers)
Closed 2 years ago.
I can't find a way to put an entry in read that contains spaces? I want to put directories in the "Enter directory to be cleaned:" read. I think it is reading the spaces as separate variables. Input would be something like /home/user/apple sauce The "cleaning" is just removing special characters from filenames.
#!/bin/bash
read -p "Enter directory to be cleaned: " directory
echo "Current Directory Structure"
/usr/bin/ls -la $directory
read input
if [ "$input" == "y" ]
then
echo "Cleaning files..."
for file in $directory; do mv $file $(echo "$file" | sed -e 's/[^A-Za-z0-9._-]/_/g'); done &
else
stop
fi
Another issue I am facing is the cleanup is repeating the entire directory when it creates the new filename. If I run that for file in *; do mv "$file" $(echo "$file" | sed -e 's/[^A-Za-z0-9._-]/_/g'); done & command in the directory itself, it just creates the new filename. If I specify the directory it writes out the whole directory:
++ sed -e 's/[^A-Za-z0-9._-]/_/g'
++ echo '/home/apples/scratch/test1/test:something?'
+ mv '/home/apples/scratch/test1/test:something?' _home_apples_scratch_test1_test_something_
I want it to just change the filename but having issues. Any help is thankful.
I think it is reading the spaces as separate variables
It does not, as you can easily verify with this:
read -p 'Enter string:' x
echo "Entered: >>>$x<<<"
If you dislike quoting your variables (to avoid word splitting), you may consider switching from bash to Zsh. Where you have to write "$x" in bash, you would simply write $x in Zsh.
Hence, you would have to write
for file in "$directory"
but this would loop just one iteration, with file bound to the content of the variable directory. For looping over the entries in this directory, you would do a
for dirent in "$directory"/*
Okay, I've written a shell script to read a file with the format:
shortcut1 /path/to/directory1
shortcut2 /path/to/directory2
and its supposed to read the file and build aliases such that typing shortcut1 cd's me into the mapped directory. The problem is, any of the aliases set in the loop don't persist outside of the script.
Firstly I tried just running the script.
. ./build_shortcuts.sh "~/.shortcuts"
where the file ~/.shortcuts contains
dl ~/Downloads
music /music
dtop ~/Desktop
This didn't work. Then I tried setting some aliases outside of the loop. Such as alias hello='world'; alias world='hellob'. I reran the script, typed alias to get a list of aliases and it did include hello and world as aliases, but not any of those set in the loop.
Then I thought maybe the loop isn't setting them at all, so I added alias as the final command in the script so it would print out the aliases at the end; in this case it did include the aliases but they still didn't persist in my session.
build_shortcuts.sh
script="$(cat $# | sed -r -e 's/#[A-Za-z0-9 ]*$//' -e '/^\s+/s/^\s+//' -e '/^\s*$/d' -)"
# strip comments, entry level indentation & empty lines (in that order) from filestream
echo "${script}" | while read shortcut; do
cut=$(echo "${shortcut}" | awk '{ print $1 }')
dest=$(echo "${shortcut}" | awk '{ $1=nil; print $0 }')
dest="${dest:1}" # trim leading whitespace character
alias "${cut}" &>/dev/null
if [ $? = 0 ]; then
echo "Warning: shortcut \"${cut}\" already exists" >&2
continue # by default, skip overwriting shortcuts
fi
echo alias ${cut}="'cd ${dest}'"
alias "${cut}"="'cd ${dest}'"
done
I want the aliases set in the loop within the script to exist outside of the script. Currently they don't.
I'm running on "GNU bash, version 5.0.7(1)-release (x86_64-pc-linux-gnu)" on arch linux.
From the Bash manual page (the section on Pipelines):
Each command in a pipeline is executed as a separate process (i.e., in a subshell)
Since the loop is done as part of a pipe, it will be a subshell, and the alias command you do in the subshell will only be set for that subshell.
A possible work-around would be to save the aliases to a list, and then perform the actual alias commands in a second loop, a loop which is not part of a pipe or a subshell.
Your script can be reduced a bit: it doesn't need to call out to so many external tools.
while read -r cut dest; do
if alias "${cut}" &>/dev/null; then
echo "Warning: shortcut \"${cut}\" already exists" >&2
else
echo alias ${cut}="'cd ${dest}'"
alias "${cut}"="'cd ${dest}'"
fi
done < <(
sed -E -e 's/#[A-Za-z0-9 ]*$//' -e '/^\s+/s/^\s+//' -e '/^\s*$/d' "$#"
)
after "done", I'm redirecting input from a process substitution: this avoids the "while read" loop from running in a subshell.
This question already has answers here:
Read glob from command line in Bash
(3 answers)
Closed 5 years ago.
I am trying to make a delete script which uses regex to move all matching files to a Trash folder in my home directory. I want to be able to use the same syntax as the vanilla rm command, but without it deleting it permanently. I can't seem to get it to run through all the matching files in the pwd. It will move one file, then exit. Here is my script.
file=$1
for i in $file; do
mv "$file" "/home/totallykvothe/Trash/$i"
done
exit 0
Pretty simple. I don't know why it isn't working. Thank you in advance.
When you run ./yourscript *.txt, *.txt isn't just one argument that's put into $1; instead, it's a glob that's expanded by the shell (to be clear -- not the shell running your script, but the shell that starts your script) into a list of arguments. The first goes in $1, the second in $2, etc.
Thus:
for i in "$#"; do
mv -- "$i" "/home/totallykvothe/Trash/$i"
done
This question already has answers here:
Brace expansion with variable? [duplicate]
(6 answers)
Closed 7 years ago.
I've got several files in a folder, with the following names:
FILE_201.txt
FILE_206.txt
FILE_215.txt
FILE_223.txt
FILE_229.txt
FILE_232.txt
I want to select files between two values (e.g. between "210" and "230").
From the command line, running
ls -1 FILE_{210..230}.txt
lists the desired files; no problem. However, if I run the following Bash script,
#!/bin/bash
ls -1 FILE_{$1..$2}.txt
passing 210 and 230 as arguments to it, it doesn't work.
What am I doing wrong?
The problem isn't about running the command at the command line or from a script. You can check that for yourself, by running the following at the command line:
$ set 210 230 # assigns variables $1 and $2 the values "210" and "230", resp.
$ ls -1 FILE_{$1..$2}.txt
ls: FILE_{210..230}.txt: No such file or directory
As you can see, you get the same error as the one raised by your script file. The problem is that brace expansion happens before variable expansion.
In this case, by the time, $1 and $2 get expanded to 210 and 230, it's too late for the range to be interpreted as such; the { .. } part simply sticks around, without any special meaning attached to it.
Anyway, using ls here is a bad idea, because you're going to get an error for each filename in the range that doesn't match an existing file. You'd be better off using a combination of a for loop and seq, as in this answer:
#!/bin/bash
# test.sh
for n in $(seq $1 $2); do
f="FILE_$n.txt"
if [ -e $f ]; then
printf $s\\n "$f"
fi
done
Example:
$ touch FILE_209.txt
$ touch FILE_213.txt
$ touch FILE_224.txt
$ touch FILE_232.txt
$ bash test.sh 210 230
FILE_213.txt
FILE_224.txt
In case anyone is interested, you need to "eval" your line. i.e.
eval "ls FILE_{$1..$2}.txt
This question already has answers here:
How do I get the directory where a Bash script is located from within the script itself?
(74 answers)
Closed 9 years ago.
So I have one bash script which calls another bash script.
The second script is in a different folder.
script1.sh:
"some_other_folder/script2.sh"
# do something
script2.sh:
src=$(pwd) # THIS returns current directory of script1.sh...
# do something
In this second script it has the line src=$(pwd) and since I'm calling that script from another script in a different directory, the $(pwd) returns the current directory of the first script.
Is there any way to get the current directory of the second script using a simple command within that script without having to pass a parameter?
Thanks.
I believe you are looking for ${BASH_SOURCE[0]}, readlinkand dirname (though you can use bash string substitution to avoid dirname)
[jaypal:~/Temp] cat b.sh
#!/bin/bash
./tp/a.sh
[jaypal:~/Temp] pwd
/Volumes/Data/jaypalsingh/Temp
[jaypal:~/Temp] cat tp/a.sh
#!/bin/bash
src=$(pwd)
src2=$( dirname $( readlink -f ${BASH_SOURCE[0]} ) )
echo "$src"
echo "$src2"
[jaypal:~/Temp] ./b.sh
/Volumes/Data/jaypalsingh/Temp
/Volumes/Data/jaypalsingh/Temp/tp/
Please try this to see if it helps
loc=`dirname $BASH_SOURCE`