command alias with appended commands - bash

I'm trying to write a bash alias which would take a command:
$ ptex example.tex
and run:
$ pdflatex example.tex && rm !(*.tex|*.pdf|*.bib)
The thing I don't understand how to do is to get the argument in the right place and then append the remove command.
Or if there is an option for pdflatex which would not generate the additional files, that would be even better, but I've looked and never found one.
Thanks in advance!

Can't do that with an alias, they're not that flexible. Functions however, are perfectly suited:
ptex() {
pdflatex "$1" && rm !(*.tex|*.pdf|*.bib)
}

Related

command substitution not working in alias?

I wanted to make an alias for launching a vim session with all the c/header/makefiles, etc loaded into the buffer.
shopt -s extglob
alias vimc="files=$(ls -A *.?(c|h|mk|[1-9]) .gitconfig [mM]akefile 2>/dev/null); [[ -z $files ]] || vim $files"
When I run the command enclosed within the quotations from the shell, it works but when run as the alias itself, it does not. Running vimc, causes vim to launch only in the first matched file(which happens to be the Makefile) and the other files(names) are executed as commands for some reason(of course unsuccessfully). I tried fiddling around and it seems that the command substitution introduces the problem. Because running only the ls produces expected output.
I cannot use xargs with vim because it breaks the terminal display.
Can anyone explain what might be causing this ?
Here is some output:
$ ls
Makefile readme main.1 main.c header.h config.mk
$ vimc
main.1: command not found
main.c: command not found
.gitignore: command not found
header.h: command not found
config.mk: command not found
On an related note, would it be possible to do what I intend to do above in a "single line", i.e without storing it into a variable files and checking to see if it is empty, using only the output stream from ls?

When creating symbolic links on ubuntu I sometimes get an odd result

I'm trying to create a bunch of symbolic links for all the files in a directory. It seems like, when I type this command in the shell manually, it works just fine, but when I run it in a shell script, or even use the up arrow to re-run it, I get the following problem.
$ sudo ln -s /path/to/my/files/* /the/target/directory/
This should create a bunch of sym links in /path/to/my/files and if I type the command in manuall, it indeed does, however, when I run the command from a shell script, or use the up arrow to re-run it I get a single symbolic link in /the/target/directory/ called * as in the link name is actually '*' and I then have to run
$ sudo rm *
To delete it, which just seems insane to me.
When you run that command in the script, are there any files in /path/to/my/files? If not, then by default the wildcard has nothing to expand to, and it is not replaced. You end up with the literal "*". You might want to check out shopt -s nullglob and run the ln command like this:
shopt -s nullglob
sudo ln -s -t /the/target/directory /path/to/my/files/*
Maybe the script uses sh and your using bash when executing the command.
You may try something like this:
for file in $(ls /path/to/my/files/*) do
ln -s "${file}" "/the/target/directory/"${file}"
done

Difference between alias rm and /bin/rm

What is the difference between using /bin/rm abc.txt and the times when sometimes you have to alias rm which is then performed with rm abc.txt
/bin/rm will always refer to the binary rm command on your system. If you just write rm abc.txt one of these may happen:
Your shell implements rm directly as a builtin function or there is a shell function called rm (no external command is run).
rm has previously been aliased (with alias rm=<substituted-command>) to mean something different. Usually the aliased command is similar in function but it does not have to be.
If none of the above is applicable, the shell looks up the external command in /bin and runs it.
You can use alias to see all defined aliases. Also check out the command -V shell builtin which can tell you if a given command is an external command, shell function, builtin or special builtin.
A typical reason to create an alias for rm is to add the -i or -I option. In "interactive" mode rm will ask for confirmation before deleting anything.
$ alias rm="/bin/rm -i"
$ rm myfile
rm: remove regular file ‘myfile’? _

How to wrap multiple subdirectories mkdir command

I want to create multiple subdirectories.
My command is:
mkdir -p dir1/{dir1.1/{dir1.1.1,dir1.1.2},dir1.2,dir1.3}
It works, result is:
dir1
dir1.1
dir1.1.1
dir1.1.2
dir1.2
dir1.3
However I want to make this command look nicer (more readable). Tried to:
mkdir -p \
dir1/{\
dir1.1/{\
dir1.1.1,\
dir1.1.2},\
dir1.2,\
dir1.3}
And this doesn't work. Result is:
ls *
dir1 dir1.1 dir1.1.1, dir1.1.2}, dir1.2, dir1.3}
How can I wrap such mkdir command?
Try the following:
eval mkdir -p `echo \
dir1/{\
dir1.1/{\
dir1.1.1,\
dir1.1.2},\
dir1.2,\
dir1.3}\
| sed -E 's/\s*//g'`
Explanation: Your original code introduces spaces into the parameter, so instead of calling
mkdir -p dir1/{dir1.1/{dir1.1.1,dir1.1.2},dir1.2,dir1.3}
You are actually calling the command with the following parameters:
mkdir -p dir1/{ dir1.1/{ dir1.1.1, dir1.1.2}, dir1.2, dir1.3}
And this is why you got the wrong directories created. Therefore, to solve this, I first stripped the whitespaces using sed, and then used eval to evaluate the resulting command. This solution should work for simple cases, but some special characters within the directory names (such as white spaces) may cause issues.
Hope this helps!
If you want readable, just call mkdir multiple times. I doubt that directory creation is going to form any kind of bottleneck in your program.
mkdir dir1
mkdir -p dir1/dir1.{1,2,3}
mkdir -p dir1/dir1.1/dir1.1.{1,2}
The problem is the whitespace in the beginning of each line, which causes the lines to be treated as different arguments of the mkdir command. To overcome this, you can do:
mkdir -p \
dir1/{\
dir1.1/{\
dir1.1.1,\
dir1.1.2},\
dir1.2,\
dir1.3}
with no whitespace in the beginning. Whether this is more readable than the first command is debatable.

Autocomplete files across multiple directories

I tried to write a bash-script for execute a command with a prefix ("DRI_PRIME=1 glxspheres" for example). This is my current script:
#!/bin/bash
_graphic() {
export IFS=":"
PATHCONTENT=()
for CONTENTPATH in $PATH; do
PATHCONTENT+=$(ls $CONTENTPATH)
done
COMPREPLY=$PATHCONTENT;
}
complete -F _graphic graphic
DRI_PRIME=1 "$#"
But this script doesnt autocomplete the folders in the $PATH-variable. What is wrong with this?
I'm not 100% sure what the question is, but it seems that you want to have a way of telling
$ graphic my_app param blah
and it will actually run
$ DRI_PRIME=1 my_app param blah
If that is so, it's rather easy, bash itself does that for you:
$ cat a.sh
function graphic {
DRI_PRIME=1 "$#"
}
complete -A command graphic
complete -A command makes bash to suggest command names (you used complete -F _graphic which makes bash call function to obtain possible completions).

Resources