Muttrc: how to source a file in muttrc's directory - relative-path

I have a muttrc file which sources a secondary file mutt-secrets which resides in its same directory. But I have what appear to be two conflicting needs:
Be free to reference the muttrc file from any working directory
Be free to move it (and mutt-secrets) without having to edit muttrc to change the source path for mutt-secrets
At present, the first line of my muttrc says: source mutt-secrets. That works fine when I run mutt from within the directory where the two file reside, but if I run mutt from elsewhere and reference muttrc with a -F flag, then mutt can find muttrc, but muttrc can't find mutt-secrets.
How can I solve this?

Use absolute paths. For example:
source ~/.mutt/mutt-secrets

TL;DR one-line solution:
source `lsof -c mutt -Fn | grep '/muttrc$' | sed 's|^n||; s|/muttrc$||;'`/mutt-secrets
or, if you want to reuse the muttrc directory, you can save it to a custom variable:
set my_muttrc_dir = `lsof -c mutt -Fn | grep '/muttrc$' | sed 's|^n||; s|/muttrc$||'`
source $my_muttrc_dir/mutt-secrets
If you want to see the output of the command when you launch mutt, you can put this line in your muttrc:
echo `lsof -c mutt -Fn | grep '/muttrc$' | sed 's|^n||; s|/muttrc$||'`
Assumptions: the Mutt process is called mutt and the Mutt's initialization file is called muttrc. Furthermore, you could get in trouble if you have more than one Mutt instance running (for example if you launch in parallel two or more Mutt instances with different initialization files, because the command may select the wrong path).
Explanation
The idea is to look for muttrc full path in the list of open files by Mutt. We can get this list using lsof command (it has to be installed in your system), then extract the full path by parsing the lsof output with grep and sed commands.
This approach is viable because Mutt's initialization files support the use of external command's output with backticks (``). When Mutt encounter and execute our command enclosed in backticks (``), it is in the process of reading the muttrc file, so the muttrc file appears in the list of currently open files by Mutt. This enables us to use the lsof command.
lsof parameters
-c mutt: list open files of process named mutt;
-Fn: for each element, print only the name (it is the path in our case). Because of lsof output format, the path will be prefixed with the character n.
grep and sed
We use grep to select the line which contains muttrc file path, assuming the filename is exactly muttrc. Then we clean the lsof output with sed by both removing the n character at the beginning of the line and the /muttrc string from the end of the line. This way we get the path of the directory containing the muttrc file.
There is a cleaner solution?
Mutt expands relative paths inside initialization files from its current working directory, i.e. from the directory you launch Mutt. It supports a mechanism that allows path's expansion relatives to something different, but the "initialization file directory" or something similar are not available. See here.
I neither found a way to get the -F <path> option you pass to the mutt command inside the initialization file.
References
backticks in Mutt's initialization file;
current directory;
_mutt_buffer_expand_path, source code
source_rc, source code
source_rc call, source code
Tested with: Mutt 2.0.5, lsof 4.93.2, GNU grep 3.7, GNU sed 4.7.

Related

make: Convert .pdf files in a folder to .txt files without using loops

I want to convert all .pdf files in a folder into .txt files with make without using loops and with the help of pdftotext. The new .txt files shall keep the original file name. Additionally, the new file gets a new file extension.
Example:
test1.pdf --> test2.newextension
Everything's written within a Makefile file. I start the conversion by typing in "make converted" in my console.
My first (miserable) attempt was:
converted:
#ls *.pdf | -n1 pdftotext
However, there are 3 things still missing with it:
It doesn't repeat the process
The new file extension isn't being added to the newly created files.
Is the original name being kept or being given to the pdftotext function?
I used to program with the bash and Makefile is completely new to me. I'd be thankful for answers!
You can refer to this simple example:
SOURCES ?= $(wildcard *.pdf)
%.txt: %.pdf
pdftotext $< $#
all: $(SOURCES:%.pdf=%.txt)
clean:
rm -f *.txt
If no SOURCE was defined, it'll just try to get all *.pdf files from the local directory.
Then we define a pattern rule teaching make how to make *.txt out of *.pdf.
We also define target all that tried to make a txt file for each .pdf file in SOURCES variable.
And also a clean rule deleting quietly all .txt files in current dir (hence be careful, potentially dangerous).

Is there a way to download multiple PDF's that are linked on a website?

I am trying to download a bunch of PDF's from the federal reserve archives but I have to click on a link and then view the PDF before I can download. Is there a way to automate this?
Example: https://fraser.stlouisfed.org/title/5170#521653 is a link to speeches and then you have to click the title, then view pdf, then the actual download button.
All of the remote .pdf files follow the path format:
https://fraser.stlouisfed.org/files/docs/historical/frbatl/speeches/guynn_xxxxxxxx.pdf
where each x is a placeholder for a digit.
So, yes, it's very easy to download a bunch of these PDFs in one go using the command-line in Terminal or whatever shell program you have access to.
If you're in a *nix-based operating system (including MacOS), that's good because your shell probably already has a command utility called curl installed. Windows may have it too, I'm not sure; I don't use Windows.
If you're using Windows, you'll have to make some tweaks to the code below, because the folder structures and file naming conventions are different, so the first couple of commands won't work.
But, if you're happy to proceed, open up a Terminal window, and type in this command to create a new directory in your Downloads folder, into which the .pdf files will be downloaded:
mkdir ~/Downloads/FRASER_PDFs; cd ~/Downloads/FRASER_PDFs
Hit Enter. Next, If there's no error, copy-n-paste this long command and then hit Enter:
curl --url \
"https://fraser.stlouisfed.org/files/docs/historical/frbatl/speeches/guynn_{"$(curl \
https://fraser.stlouisfed.org/title/5170#521653 --silent \
| egrep -io -e '/files/docs/historical/frbatl/speeches/guynn_\d+\.pdf' \
| egrep -o -e '\d+' | tr '\n' ',')"}.pdf" -O --remote-name-all
You can see this uses the URL you supplied in your question, from which that command retrieves all the .pdf links. If you need to do the same with other similar pages, provided they all use the same URL format, you can just substitute 5170#521653 with whatever page reference contains another list of .pdfs.

How to launch a .bat file in VB without associating the file with the program that launched it?

Ok, the the question looks freakish, but this is sort of a continuation of the question I posted
here.
So, I create a .bat file in Visual Studio with certain lines and launch it, but it basically doesn't find the files it needs, but if I launch the .bat file it created manually, it works.
The problem, as far as I see it, is that the .bat file the program launches isn't the same as the one that is created in the folder?
The .bat files use the command line interface of Asesprite found here, e.g. :
#set ASEPRITE="C:\Program Files\Aseprite\aseprite.exe"
%ASEPRITE% --batch animation.ase --scale 2 --save-as animation-x2.gif
I'm not sure which part of the VB code I'd need to share, so ask if needed.
The error in .bat goes something like:
C:\Users\User\Desktop\aseConverter\aseConverter\bin\Debug>"E\Asesprite\asesprite.exe" --batch skeleton2_gib3.ase --scale 1 --save-as skeleton2_gib3.gif
File not found: "skeleton2_gib3.ase"
Error loading file "skeleton2_gib3.ase"
A document is needed before --save-as arguement
The first line should not be the Debug folder, but the location the .bat file was created in. I've no idea how to fix it.
It SHOULD be
C:\Users\User\Desktop\skeleton>"E\Asesprite\asesprite.exe" --batch skeleton2_gib3.ase --scale 1 --save-as skeleton2_gib3.gif
The problem here is that the batch file references files without path. Therefore the files must be in current working directory of the batch file.
But the batch file respectively command line interpreter cmd.exe is called by the VB.net without setting the working directory. Therefore the current working directory set by Windows for the batch file is the same as of the starting VB.net application.
But the starting application creates the batch file and the other files in a different directory, not in its own current working directory.
One solution is changing current working directory inside batch file to the directory the batch file is stored. This can be done by referencing argument 0 of the batch file which contains name of batch file with complete path.
What does %~dp0 mean, and how does it work? explains how to get drive and path of batch file.
Therefore one solution is to use a batch file like below:
#echo off
cd /D "%~dp0"
set "ASEPRITE=%ProgramFiles%\Aseprite\aseprite.exe"
"%ASEPRITE%" --batch animation.ase --scale 2 --save-as animation-x2.gif
See help output after executing cd /? in a command prompt window for meaning of parameter /D (change also drive if necessary).
An explanation for %~dp0 can be read on running call /? or for /? in a command prompt window.
Another possibility would be the usage of following batch code:
#echo off
pushd "%~dp0"
set "ASEPRITE=%ProgramFiles%\Aseprite\aseprite.exe"
"%ASEPRITE%" --batch animation.ase --scale 2 --save-as animation-x2.gif
popd
The difference to command cd is explained in help which is output in a command prompt window after executing pushd /?.
Best would be to create the batch file with all files referencing with complete path, name and file extension.

zsh survive glob failure

I have checked out a project, the project contains a .gitignore file.
The contents of this file are like so
vx1% head .gitignore
./deps
/*.exe
/*.la
/.auto
.libs
ChangeLog
Makefile
Makefile.in
aclocal.m4
autom4te.cache
I want to
read the file line by line
for each line read, list the actual files that are being ignored
finally I want to tweak the script to delete those files
The reason for wanting to do this - is that I don't trust the project Makefile to fully clean up it's generated files.
Notes
As you can see, the .gitignore uses some globs that I need to modify before running the commands, otherwise the glob will resolve to my root directory.
What I already know
To dynamically evaluate an arbitrary string as a glob pattern
DYN="*.c"
print $~DYN
To strip the leading /, if it exists
DYN="/*.c"
print ${~DYN/#//}
What I've got
cat .gitignore | while read i; do echo $i ; print ${~i/#//} ; done
The problem
The first glob failure that this loop encounters, it terminates with error
zsh: no matches found: *.exe
What I want
The 'script' should keep going through each line of the file, trying each line in turn.
I answered this myself, answer is below
Found the answer on the zsh mailing list, in typical Zsh fashion - it's very simple when you know how, and impossible otherwise.
print *.nosuchextension(N)
The (N) glob parameter prevents raising an error on match failure.

Problem with multiple listings of the same file in RPM spec

I have some problems with an rpm spec file that is listing the same file multiple times. For this spec we do some normal compilation and then we have script that copies everything to the buildroot. Within this buildroot we have a lot of generic scripts that need to be installed on the final system, so we just list this directory.
However the problem is, that one of the scripts might be changed and configuration options might be changed within the script. So we list this script with different attributes as %config. However this means the script is defined multiple times with conflicting attributes, so rpmbuild complains and does not include the script at all in the installation package.
Is there a good way to handle this problem and to tell rpmbuild to only use the second definition, or do we have to seperate the script into two parts, one containing the configuration and one containing the actual logic?
Instead of specifying the directory, you can create a file list and then prune duplicate files from that.
So where you have something like
%files
%dir foo
%config foo/scriptname
You modify those parts to
find $RPM_BUILD_ROOT -type f | sed -e "s|^$RPM_BUILD_ROOT||" > filelist
sed -i "\|^foo/scriptname$|d" filelist
%files -f filelist
%config foo/scriptname
You can also use %{buildroot} in place of $RPM_BUILD_ROOT.