get output of bash autocompletion for testing - unit-testing

I would like to make a unit test that tests that a bash autocompletion script correctly expands a certain string (let's assume the cursor is at the end).
(I think) I would like to be able to input a string and capture the output of COMPREPLY.
For example, suppose I would like to test that when I put git b<TAB><TAB> it offers bisect blame branch bundle. How can I get that output from a bash function?
In case that is confusing, I would like to be able to do something like:
output=$(get_compreply "git b")
echo "$output"
> bisect blame branch bundle

Here you are:
compgen -c YOUR_INPUT_BEFORE_TAB

Firstly, do you have defined completions for git? (What is the output of running complete -p?)
This page describes building compspecs: http://www.debian-administration.org/article/An_introduction_to_bash_completion_part_2
Here is a simplified example:-
$ output=$(compgen -W "bisect blame branch bundle" b)
$ echo $output
bisect blame branch bundle

Related

Golang: Compile all tests across a repo without executing them

Context
I have a repo in which multiple teams contribute integration tests.
All these tests are hidden behind //go:build integration flags, so if I want go to see or run them, I need to pass the -build integration flag to the test command.
Purpose
What I’m trying to accomplish is to compile all tests across the entirety of this repo without actually executing them (would take a long time) so I can catch build errors introduced by PRs that the default go test compilation and execution would not catch.
I see the -c flag:
-c
Compile the test binary to pkg.test but do not run it
(where pkg is the last element of the package's import path).
The file name can be changed with the -o flag.
However… one cannot use the -c flag with the -build flag:
$ go test -build=integration -c ./integrationtests/client/admin-api
go: unknown flag -build=integration cannot be used with -c
Also... one cannot use the -c flag across multiple packages:
$ go test -c ./...
cannot use -c flag with multiple packages
Any ideas?
You can use the go test -run flag and pass it a pattern you know will never match:
go test -run=XXX_SHOULD_NEVER_MATCH_XXX ./...
ok mypkg 0.731s [no tests to run]
this will catch any test compilation errors - and if there are none - no tests will be run.
If you need to pass any build tags that are typically passed during your go build process (e.g. go build -tags mytag), you can do the same during go test:
go test -tags mytag -run=XXX_SHOULD_NEVER_MATCH_XXX ./...
Full details on the -run flag from the inline (go help testflag) docs:
-run regexp
Run only those tests, examples, and fuzz tests matching the regular
expression. For tests, the regular expression is split by unbracketed
slash (/) characters into a sequence of regular expressions, and each
part of a tests identifier must match the corresponding element in
the sequence, if any. Note that possible parents of matches are
run too, so that -run=X/Y matches and runs and reports the result
of all tests matching X, even those without sub-tests matching Y,
because it must run them to look for those sub-tests.

Is there a way for changing text file names in a folder using C++

I am working with a bunch of txt files(thousands) on my project. Each txt file has 'csv' information on it. The problem is that each txt file has a random name and I cannot create a code for loading them in my project due to it. So, I want to rename them in a particular pattern to make easier the loading of the files in my work. I will use C++ for accomplish this task.
I put all the txt files in a folder but I cannot see a way of renaming them using C++. How can I do this? is there a way to do it? Can someone help me?
You can use std::filesystem::directory_iterator and std::filesystem::rename (c++17), as documented here.
Disclaimer
This answer validity is based on a comment where the author precised they were not bound to the C++ language (it may be worth editing the question, the C++ tag, and the OS). This solution may work for UNIX systems supporting bash, that is most Linux distributions and all releases of Apple's macOS prior to macOS Catalina (correct me if I'm wrong).
Bash command line
Using the following bash command should rename all the files in a folder with increasing numbers, that is:
toto.csv -> 1.csv
titi.csv -> 2.csv etc
It assumes the ordering is not important.
a=1; for i in *; do mv -n "$i" "$a.csv" ; let "a +=1"; done
To test it, you can prepare a test folder by opening a terminal and typing:
mkdir test
cd test
touch toto.csv titi.csv tata.csv
ls
Output:
tata.csv titi.csv toto.csv
Then you can run the following command:
a=1; for i in *; do mv -n "$i" "$a.csv" ; let "a +=1"; done
ls
Output:
1.csv 2.csv 3.csv
Explication:
a=1 declare a variable
for i in *; begin to iterate over all files in the folder
do mv will move (rename) a file of the list (that is, the variable $i) to a new name called a.csv
and we increment the counter a, and close the loop.
the option -n will make sure no file gets overwritten by the command mv
I assumed there was no specific criterion to rename the files. If there is a specific structure (pattern) in the renaming, the bash command can probably accommodate it, but the question should then give more details about these requirements :)

Git status showing weird untracked "path_of_file\r" files, how to remove by command line

I was in a C++ program with google unit test, gtest. I ran and built the projects.
At the end, when I ran git status, it gave some weird untracked files. I do not know where they are from, and how I should remove them please. Using bash.
> git status
On branch A
Untracked files:
(use "git add <file>..." to include in what will be committed)
"../path_of_file1\r"
"../path_of_file2\r"
"../path_of_file3\r"
nothing added to commit but untracked files present (use "git add" to track)
This did not work:
rm -f "path_to_file\r"
Thank you.
I believe git clean should work in most scenarios. I tried the rm without the "", it worked! Thank you all.
rm path_to_file\r (complete by tabs)
You can always remove all untracked (and unignored) files with git clean -f. To be safe, run git clean -n first to see which files will be deleted.
David's answer is a good one, assuming you want to do a full git clean.
Here is another option that lets you delete the files individually: Let your shell complete the file names for you, escaping them as necessary.
For example, if you type
rm path_to_file1
and press Tab, most shells will complete the filename with a proper escape sequence. The precise sequence will be shell-specific, and I'm not clear whether \r is the two characters \ and r or whether it's a single special character, but your shell will know for sure.

Copy and Rename Multiple Files with Regular Expressions in bash

I've got a file structure that looks like:
A/
2098765.1ext
2098765.2ext
2098765.3ext
2098765.4ext
12345.1ext
12345.2ext
12345.3ext
12345.4ext
B/
2056789.1ext
2056789.2ext
2056789.3ext
2056789.4ext
54321.1ext
54321.2ext
54321.3ext
54321.4ext
I need to rename all the files that begin with 20 to start with 10; i.e., I need to rename B/2022222.1ext to B/1022222.1ext
I've seen many of the other questions regarding renaming multiple files, but couldn't seem to make it work for my case. Just to see if I can figure out what I'm doing before I actually try to do the copy/renaming I've done:
for file in "*/20?????.*"; do
echo "{$file/20/10}";
done
but all I get is
{*/20?????.*/20/10}
Can someone show me how to do this?
You just have a little bit of incorrect syntax is all:
for file in */20?????.*; do mv $file ${file/20/10}; done
Remove quotes from the argument to in. Otherwise, the filename expansion does not occur.
The $ in the substitution should go before the bracket
Here is a solution which use the find command:
find . -name '20*' | while read oldname; do echo mv "$oldname" "${oldname/20/10}"; done
This command does not actually do your bidding, it only prints out what should be done. Review the output and if you are happy, remove the echo command and run it for real.
Just wanna add to Explosion Pill's answer.
On OS X though, you must say
mv "${file}" "${file_expression}"
Or the mv command does not recognize it.
Brace expansions like :
{*/20?????.*/20/10}
can't be surrounded by quotes.
Instead, try doing (with Perl rename) :
rename 's/^10/^20/' */*.ext
You can do this using the Perl tool rename from the shell prompt. (There are other tools with the same name which may or may not be able to do this, so be careful.)
If you want to do a dry run to make sure you don't clobber any files, add the -n switch to the command.
note
If you run the following command (linux)
$ file $(readlink -f $(type -p rename))
and you have a result like
.../rename: Perl script, ASCII text executable
then this seems to be the right tool =)
This seems to be the default rename command on Ubuntu.
To make it the default on Debian and derivative like Ubuntu :
sudo update-alternatives --set rename /path/to/rename
The glob behavior of * is suppressed in double quotes. Try:
for file in */20?????.*; do
echo "${file/20/10}";
done

Using two asterisks to add a file in git

I want to add a file which has a unique file name but a long preceding path (e.g. a/b/c/d/filename.java). Normally I would add this to my repository by doing
git add *filename.java.
However I have also done this before:
git add a/b/c/d/filename*
So I tried to combine the two:
git add *filename*
but this does something weird. It adds every untracked file. I can see possible reasons for failure but they all should occur in one of the previous two commands so I don't know why this is happening.
My question isn't so much about how to add a file to a git repository with just its file name (although that would be useful).
My question is what is my misunderstanding of the * operation which makes me think the above should work.
Info:
I am using Git Bash for Windows, which is based on minGW.
You're looking at globs
(not regular expressions, which are a different pattern-matching language), and they're expanded by your shell, not by git.
If you want to see how they're going to match, just pass the same glob to another command, eg.
$ ls -d *filename.java
vs
$ ls -d *filename*
(I've just added the -d so ls doesn't show the contents of any directories that match)
Since you're using git bash, and it's possible that glob expansion behaves differently from a regular shell, try
$ git add --dry-run --verbose -- *filename*
for example: this should show you how it really expands the glob and what effect that has.
Note the -- ... if you're using globs that might match a filename with a leading -, it's important to make sure git knows it's a filename and not an option.
Unfortunately, this will only show you the files which both match the glob, and have some difference between the index and working copy.
Answer from author:
The dry run helped a lot, here is what I found:
I was forgetting about the bin folder which I haven't added, so when I performed the dry run I realised it was finding two matches: filename.java and filename.class. When I changed the glob to *filename.j* it worked.
My next step was to remove the .class and try the command again: it worked! It is still unexplained why git bash added everything when it found two matches... since the dry run behaves differently from the actual run I think there must be a bug, but I think that discussion is to be held elsewhere (unless somebody thinks it isn't a bug).
You could try with git add ./**/*.java
Note: I tested with zsh, it should also work for bash as well.