Is it possible to re-create standard "desc" command indenting of comments using cleartool format string?
Example:
cleartool desc <version> outputs something like
version "<extended version path>"
created <date> by <user>
"comment line 1
comment line 2
...
comment line n"
...
Is there -fmt option to create similar output with custom format?
Not directly, regarding the indent part.
fmt_ccase man page does propose the extended version path, date, user and comment, but you can only put spaces or tabs (ie 'escape sequences') in front of each fields, not put tabs in the middle of one of those fields (like tabs in front of each lines of a comment)
cleartool descr -fmt "version \"%Xn\"\ncreated %d by %u\n\t\"%c\"" afile
Note than one of the examples seems to indicates that spaces put in front of a field are repeated for all the lines of that field:
Mimic the output from lshistory –long.
Note that in cleartool single-command mode, backslashes (\) are used to escape double quotes in the format string.
cleartool lshistory -fmt "%d %Fu (%u#%h)\n %e \"%n\"\n \"%Nc\"\n" util.c
2007-05-11T09:24:38 Anne Duvo (anne#neptune)
create version "util.c##\main\3"
"fix bug r2-307"
2007-05-10T09:09:29 Ravi Singha (ravi#mercury)
create version "util.c##\main\2"
"ready for code review"
.
.
.
Related
Trying to reformat tags in an xlm file with gnu sed v4.7 on win10 (shoot me). sed is in the path and run from the Command Prompt. Need to escape some windows command-line characters with ^.
sourcefile
BEGIN
...
<trn:description>V7906 03/11 ALFREDOCAMEL HATSWOOD 74564500125</trn:description>
...
END
(There are three spaces at the start of the line.)
Expected output:
BEGIN
...
<trn:description>V7906 03/11 Alfredocamel Hatswood 74564500125</trn:description>
...
END
I want Title Case but this does in-place to lower case:
sed -i 's/^<trn:description^>\(.*\)^<\/trn:description^>$/^<trn:description^>\L\1^<\/trn:description^>/g' sourcefile
This command changes to Title Case:
sed 's/.*/\L^&/; s/\w*/\u^&/g' sourcefile
Can this be brought together as a one-liner to edit the original sourcefile in-place?
I want to use sed because it is available on the system and the code is consistently structured. I'm aware I should use a tool like xmlstarlet as explained:
sed ... code can't distinguish a comment that talks about sessionId tags from a real sessionId tag; can't recognize element encodings; can't deal with unexpected attributes being present on your tag; etc.
Thanks to Whirlpool Forum members for the answer and discussion.
It was too hard to achieve pattern matching "within the tags" in sed and the file was well formed so the required lines were changed:
sed -i.bak '/^<trn:description^>/s/\w\+/\L\u^&/g; s/^&.*;\^|Trn:Description/\L^&/g' filename
Explanation
in-place edit saving original file with .bak extension
select lines containing <trn:description>
for one or more words
replace first character with uppercase and rest with lowercase
select strings starting with & and ending with ; or Trn:Description
restore codes by replacing characters with lowercase
source/target filename
Note: ^ is windows escape character and is not required in other implementations
I can't manage to find a way to make special edition, e.g., changing a string 'ABC' with a text 'TEXT1 TEXT2' in only files that already met a search criteria that I want.
Example: in all the files that contain the string '-FI-' replace the string 'ABC' with the string 'TEXT1 TEXT2'.
Is there a way/feature to do it please?, I have VScode 1.37.1 installed on Windows10. I want something that can be run in VScode and in worst case maybe some linux stuff can help ...
I tried for example how to make a search inside a search and edit. And I don't have enough knowledge to do it using regex.
Thank you.
Based on the clarifying comments, I interpret the question to be:
How can I replace all instances of "ABC" with "TEXT1 TEXT2" within files that also contain the string "-Fl-", starting at a given directory and recursively considering all files beneath it?
I would solve this using Cygwin shell commands rather than in VSCode.
First, let's make a file that contains the names of all the files that contain the string "-Fl-". At a bash shell, use cd to go to the directory of interest, and run:
$ grep -l -r -- '-Fl-' . > files.txt
Breaking this down:
grep searches for text within files.
The -l switch prints the file names rather than matching lines.
The -r switch searches recursively in subdirectories.
The -- switch tells grep that that is the last command line option, so subsequent words should be treated as arguments (i.e., text to search for). This is necessary because our search text begins with - and hence would otherwise be treated as an option.
The -Fl- is the text to search for (case sensitive; use the -i option for case insensitive search).
The . is the place for grep to search, and means "current directory" (plus all files and subdirectories, recursively, due to -r).
The > files.txt part says to write the results to files.txt.
Before going on, open files.txt in an editor or just cat it to the terminal to verify that it looks reasonable to you:
$ cat files.txt
Now we need to do search and replace in this list of files. This isn't so easy to do with just stock shell commands, so I've written my own script that I use to do it:
https://raw.githubusercontent.com/smcpeak/scripts/master/replace-across-files
Save that as a file called "replace-across-files". I normally put such things into $HOME/scripts, also known as ~/scripts, so I will assume you've done the same (make that directory first if necessary).
Now, go back to the directory that has files.txt and run:
perl ~/scripts/replace-across-files 'ABC' 'TEXT1 TEXT2' $(cat files.txt)
This will interactively prompt you for each occurrence. Use y (or just Enter) to accept each one individually, Y to accept all in the current file, and ! to make all replacements.
If you get perl: command not found, then you need to install Cygwin perl first.
One possible gotcha: if any of the file names contain a space, then this won't work because $(cat files.txt) splits files.txt at whitespace boundaries before putting the contents onto the command line. One way to deal with this is to use xargs instead:
$ cat files.txt | xargs -d '\n' perl ~/scripts/replace-across-files -f 'ABC' 'TEXT1 TEXT2'
Breaking this down:
cat files.txt | feeds the contents of files.txt to the next command, xargs, as its input.
xargs adds its input onto the given command line and runs it.
-d '\n' tells xargs to divide its input at newline boundaries, not any whitespace.
-f tells replace-across-files to do all replacements non-interactively. This is necessary because, due to the way xargs works, prompting for each replacement would not work.
This is pretty simple using an extension I wrote that can use the results from one search to limit the files searched in a second, third, etc. search. Using the Find and Transform extension, make this keybinding (in your keybindings.json):
{
"key": "alt+m", // whatever keybinding you want
"command": "runInSearchPanel",
"args": {
"find": ["-F1-", "ABC"],
"replace": ["", "TEXT1 TEXT2"],
"filesToInclude": ["", "${resultsFiles}"],
"triggerReplaceAll": true,
// "delay": 250 // a pause between searches, in milliseconds
}
}
"find": ["-F1-", "ABC"], runs 2 finds, first for -F1- and then for ABC.
"replace": ["", "TEXT1 TEXT2"], two replaces, but the first does nothing (it does NOT replace -F1- with an empty string).
"filesToInclude": ["", "${resultsFiles}"], the first "" clears the files to include input, and the second will populate the files to include search input with only the files that were found with the previous search.
If you wanted to start the first search in a particular directory, you could put something into that first "", like ${relativeFileDirname} for example or a few other variables or any string value representing a folder or file path.
"delay": 250 for searching larger groups of files, there must be a delay between each search if you are doing multiple searches like in the current case. This is to allow vscode to complete the previous search and populate the search results. There is a default delay of 2000 or 2 seconds but you can try shorter or longer delay values for your situation.
I am trying to reorganise images based on keywords that are found in the IPTC metadata. More specifically, I need sort images into directories based on the species name in the subject pseudo tag of exiftool.
To do this, I have compiled the keywords in a .txt file (species_ls.txt), with each keyword on a new line, as such:
Asian Tortoise
Banded Civet
Banded Linsang
...
To sort the images I have created the following for loop, which iterates through each line of the document, with sed pulling out the keyword. Here, $line_no is the number of lines in the species_ls.txt file, and image_raw is the directory containing the images.
for i in 'seq 1 $line_no'; do
sp_name=$(sed -n "${i}p" < species_ls.txt)
exiftool -r -if '$subject=~/${sp_name}/i' \
'-Filename=./${sp_dir}/%f%+c%E' image_raw`
Although the for loop runs, no conditions are being met in the -if flag in exiftool. I am assuming this is because the variable sp_name is not being passed into the condition properly.
Any suggestions, or a better way of doing this, would be appreciated.
For the line with condition, rather than using single quotes (' '), it would be better to use double quotes (" ").
The single quotes mean that the content is passed literally, meaning your variable won't get expanded.
To overcome, the $subject line expanding (which I presume you don't want), you can just put a \ in front of the $ to escape it being read as a variable.
This line should now look like:
exiftool -r -if "\$subject=~/${sp_name}/i"
Hope this helps you!
I have the following Swift function in my file Main/VProj/AppModel.swift
func createItemAndSegment(image:UIImage, completionHandler:(Item?, NSError?)->Void) {
\\[...]
}
The documentation for git log -L :<funcname>:<file> states
-L <start>,<end>:<file>
-L :<funcname>:<file>
Trace the evolution of the line range given by "<start>,<end>" (or the
function name regex <funcname>) within the <file>.
But the commands
git log -L :createItemAndSegment:Main/VProj/AppModel.swift
git log -L :'createItemAndSegment':Main/VProj/AppModel.swift
git log -L :'/createItemAndSegment/':Main/VProj/AppModel.swift
all fail with the error starting at line 1: no match
When the documentation says :<funcname> is the "function name regex", what should it look like?
The funcname should be a regular expression that matches the function name, and a literal string with no special regular expression characters should be a valid regular expression, so your first example, git log -L :createItemAndSegment:Main/VProj/AppModel.swift, should work.
However, in order for it to work, Git needs to be able to determine which lines are function declarations. It has a default regular expression that assumes that any line that begins with an alphabetic character, underscore, or dollar sign (with no leading whitespace) is the start of a function declaration, and using the -L :<funcname>:<file> syntax will be searching for a function declaration that also matches your pattern, up to the next function declaration or end of file.
In some languages, this heuristic is not appropriate. For instance, if function or method declarations are nested inside of a class and thus indented, it will not pick up on these declarations. For this, you need to define a custom function header regex. The .gitattributes section "Defining a custom hunk-header" describes how to do this. First, you would create a .gitattributes file at the top level of your project that contains something like:
*.swift diff=swift
Then in your .git/config, or your global ~/.gitconfig, you would define a regex for how to find these declarations. I don't know enough of Swift to be able to tell you for sure what the appropriate regex is, but it might be something like the following (which I based on the built in regex for Python):
[diff "swift"]
xfuncname = ^[ \t]*((class|func)[ \t].*)$
I met the same situation when trying to explain how to trace a JS function in a class using git log -L.
I ended up using the <start><end>:<file> syntax. The only problem was to find the right syntax for the <end> matcher in order to specify the exact indentation.
Here is an example:
git log -L '/myFunction (params) {/','/^ }/':myClass.js
I you read the official example in the man page, you've seen that syntax:
git log -L '/int main/',/^}/:main.c
If you try that one with my previous example you'll get an error:
$ git log -L '/myFunction (params) {/',/^ }/:myClass.js
fatal: Invalid object name '}/'.
The solution is to use (single) quotes around the <end> expression: /^ }/=> '/^ }/'.
I hope this would help.
The funcname should be a regular expression that matches the function name
Make sure said funcname is not $, or that would trigger an infinite loop, as documented in "Why does '$' for funcname in git log -L cause an infinite search?".
larsks proposed a patch which should be part of Git 2.40 (Q1 2023).
When given a pattern that matches an empty string at the end of a line, the code to parse the "git diff"(man) line-ranges fell into an infinite loop, which has been corrected with Git 2.40 (Q1 2023).
See commit 4e57c88 (19 Dec 2022) by Lars Kellogg-Stedman (larsks).
(Merged by Junio C Hamano -- gitster -- in commit 3f2e4c0, 02 Jan 2023)
line-range: fix infinite loop bug with '$' regex
Signed-off-by: Lars Kellogg-Stedman
When the -L argument to "git log"(man) is passed the zero-width regular expression $" (as in "-L :$:line-range.c"), this results in an infinite loop in find_funcname_matching_regexp().
Modify find_funcname_matching_regexp to correctly match the entire line instead of the zero-width match at eol and update the loop condition to prevent an infinite loop in the event of other undiscovered corner cases.
The primary change is that we pre-decrement the beginning-of-line marker ('bol') before comparing it to '\n'.
In the case of '$', where we match the '\n' at the end of the line and start the loop with bol == eol, this ensures that bol will find the beginning of the line on which the match occurred.
You will now get:
$ git log -L :$:main.go
fatal: -L parameter '$' starting at line 1: no match
My shell has a call to 'fortune' in my .login file, to provide me with a little message of the day. However, some of the fortunes begin with one leading whitespace line, some begin with two, and some don't have any leading whitespace lines at all. This bugs me.
I sat down to wrapper fortune with my own shell script, which would remove all the leading whitespace from the input, without destroying any formatting of the actual fortune, which may intentionally have lines of whitespace.
It doesn't appear to be an easy one-liner two-minute fix, and as I read(reed) through the man pages for sed and grep, I figured I'd ask our wonderful patrons here.
Using the same source as Dav:
# delete all leading blank lines at top of file
sed '/./,$!d'
Source: http://www.linuxhowtos.org/System/sedoneliner.htm?ref=news.rdf
Additionally, here's why this works:
The comma separates a "range" of operation. sed can accept regular expressions for range definitions, so /./ matches the first line with "anything" (.) on it and $ specifies the end of the file. Therefore,
/./,$ matches "the first not-blank line to the end of the file".
! then inverts that selection, making it effectively "the blank lines at the top of the file".
d deletes those lines.
# delete all leading blank lines at top of file
sed '/./,$!d'
Source: http://www.linuxhowtos.org/System/sedoneliner.htm?ref=news.rdf
Just pipe the output of fortune into it:
fortune | sed '/./,$!d'
How about:
sed "s/^ *//" < fortunefile
i am not sure about how your fortune message actually looks like, but here's an illustration
$ string=" my message of the day"
$ echo $string
my message of the day
$ echo "$string"
my message of the day
or you could use awk
echo "${string}" | awk '{gsub(/^ +/,"")}1'