zsh survive glob failure - error-handling

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.

Related

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

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.

Error in running trace32 with command line

I have a .cmm file which helps in debugging of Qcomm chipsets.
This file has a line : cd ../../../../../modem_proc
When I run this same cmm file using T32 GUI, it runs fine and does the work. But when I am trying to run the same file using windows command line using,
C:\T32\bin\windows64>t32mqdsp6.exe -c C:\T32\config.t32 -s D:\path\to\xxx.cmm
Following error is thrown in T32: syntax error in B::cd ../../../../../modem_proc
What am I missing here? I have no hands-on experience with T32 what-so-ever.
The problem probably results from different working directories. Type
PRINT OS.PWD()
in the GUI and add it to the top of the script. I'd suspect they are different.
Don't use working directory relative paths, instead use paths relative to the script, e.g.
CD ~~~~/../../../../modem_proc
The four tilde (~) symbols mean "directory of the currently executed script". There's still a possible issue with this solution when using multiple GUIs and the intercom, but for most use-cases this should be OK.
When starting TRACE32 (up to build 99518) without option "-s", it starts a default script t32.cmm form your TRACE32 installation directory. But t32.cmm is not executed, when "-s" is used.
So probably your t32.cmm is changing your working directory. If so you can fix the issue by adding the line
DO ~~/t32.cmm
to the top of your script xxx.cmm.
See also https://www.lauterbach.com/frames.html?help_autostart.html
The default working path is also set by the TRACE32 configuration file. That is the file passed with "-c". So if your are using a different configuration file than C:\T32\config.t32 when starting your TRACE32 GUI the normal way, then you should use that configuration file also when starting TRACE32 from the command line.
To get the path of the configuration file usually used, start TRACE32, execute command AREAand then command PRINT OS.PCF()
Furthermore dev15 is probably right here https://stackoverflow.com/a/53671657/4727717:
Use paths relative to the PRACTICE script (cmm-file) by starting each path with four tildes.

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).

unix command 'mv' failure

I am using move command mv -f $file1 $file2 to move a file from source directory to a destination directory. I am getting a failure message as:
mv: cannot create regular file $file2:File exists
Could you let me know on the reason for such failures from move command?
Are there any ways to solve this error?
This is caused by race condition. Your were running multiple mv in your scripts.
Does that file really exist? If it exists, and you are SURE that you want to overwrite it, add the -f flag, which will force the command to continue;
mv -f file1 file2
This error can be caused by a privileges conflict and occasionally by using illegal characters in the file name. Make sure there are no unusual special characters in the file's name and verify that there is not already a file with the same name in the directory that the file is being moved to. You might need to use ls -l from above target directory to see if the privileges settings will allow you to read/write to the directory.

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.