UNIX: Strange output if piped to less - unix

If I execute ls command with pipe to less, I get strange output
ESC[00mESC[00mfile1.ccESC[00m
ESC[00file2.ccESC[00m
ESC[00file3.ccESC[00m
(means ESC string in between).
Without ls, the output is:
file1.cc file2.cc file3.cc
How to correct this?

I'm guessing that you have the --color=always option to ls set, either through an alias, functions or the LS_COLORS environment variable and ls is sending color directives to a non-terminal (that is, your pipe to less).

Use less -R or set the LESS environment variable to -R.

What you're seeing are ANSI escape sequences for setting colors. Run ls --color=no.

You need to make less output raw control characters using less -r.

Related

Zsh: string getting expanded

I am trying to create a Zsh version of the Command Line Window in Vim.
I want to use the moreutils program vipe to pipe history into.
For that purpose, I have something like:
EDITOR='nvim -c "normal G"'
fc -ln | vipe
Here, fc -ln represents the history, and $EDITOR represents the program that I'll be piping into.
The problem is, the above does not work.
In this specific case I get the file G" opened. It seems that the double quotes to surround the command are not being recognized.
Nor could I get it to work with any other combination of single quotes, double quotes or variables.
How can I pass in the string "normal G"?
vipe splits its arguments by space, so it is not possible to use multi-word c options. I resolved this by creating a .vim file and using nvim -S file.vim.

can't stop ZSH autocorrect

I've set this in my ~/.zshrc
DISABLE_CORRECTION="true"
DISABLE_AUTO_TITLE="true"
unsetopt correct
Still, ZSH is constantly trying to autocorrect.
What is the setting, configuration, etc.. that I can set to stop this super annoying behavior?
You almost got it. The option you're looking for is unsetopt correct_all
From man zshoptions:
CORRECT (-0)
Try to correct the spelling of commands. Note that, when the HASH_LIST_ALL option is not set or when some directories in the path are not readable,
The shell variable CORRECT_IGNORE may be set to a pattern to match words that will never be offered as corrections.
CORRECT_ALL (-O)
Try to correct the spelling of all arguments in a line.
The shell variable CORRECT_IGNORE_FILE may be set to a pattern to match file names that will never be offered as corrections.

Grep: Recursive option produces unexpected behavior when fed pipe-input

I've been using this utility successfully for many years, in many environemnts. But I'm noticing that on one particular environment, it produces very unexpected results.
grep -r 'search-term1' . | grep 'search-term2'
The above code greps recursively for all instances of search-term1, in the current-dir. The results are then piped to another grep, which selects only those lines that also contain search-term2. This works exactly as I would expect.
grep -r 'search-term1' . | grep -r 'search-term2'
The only difference in the above code is that the -r recursive flag in specified in both grep commands. I would expect the behavior to not change for this particular case. After all, the input to the 2nd grep is a pipe-input, and there's nothing further to be found recursively.
I have been using the command successfully, for many years, in many different environments (both unix and mac-os). However, the most recent environment that I started working in (unix), breaks the above behavior. The second piped grep searches for all instances of search-term2, not only in the piped-input, but also all files in my current directory. Because of this, instead of getting only results that contain both search-terms, I get all results in current-dir that contain the 2nd search term.
Is there any reason why this one particular environment produces this odd behavior? Is there any way I can avoid this, while still preserving the -r flag?
FAQ:
Q: Why am I using the -r flag on a piped input?
Ans: I actually have grep saved as an alias, with many different options and flags that I always want to use as a default. The recursive flag is one of them. I would like to always use this alias, instead of having to type out all the flags every time.
Q: If you want to search for all instances matching both search terms, why not do (insert-superior-method-here) instead?
Ans: You're probably right. I'm sure there are things I can change in my usual habits that would workaround this issue. However, as intellectual curiosity, I would like to find out why recursive-greps-on-pipes work as intended on most environments, but not all, and if that can somehow be resolved.
The -r flag to grep changed in grep version 2.11 (release notes to implicitly use the working directory as the input if no file arguments are given.
If no file operand is given, and a command-line -r or equivalent
option is given, grep now searches the working directory.
You aren't giving the second grep any file arguments so it defaults to the current directory despite there being pipe input.
Try grep -r 'search-term1' . | grep -r 'search-term2' - as a workaround.
grep -r 'search-term1' . | grep -r -d skip 'search-term2' may also work around the problem.

Fill in the latest used file in the current directory

I am looking for a way to quickly access the latest file/directory on the command line, preferably in ZSH.
ls -d *(om[1])
Gives me just that, and if I want to use to with a command, e.g. less *(om[1])
This works as well.
However, it is tedious to type all the brackets, and I use this a lot - hence I am looking for a way to create a shortcut for this string.
I've created a function in the .zshrc-file
lf(){
ls -d *(om[1])
}
, which I can use like this:
less <$(lf)
less <`lf`
, but I find this still less than ideal.
less |lf
does not work.
Is there a way to quickly access the latest file without the use of "hard to type characters"? Ideally, it would just be something along the lines of
less LATEST
Any ideas?
You could use the _most_recent_file (^Xm).
_most_recent_file (^Xm)
Complete the name of the most recently modified file matching the pattern on the command line (which may be blank). If given a numeric argument N, complete the Nth most recently modified file. Note the completion, if any, is always unique.
-- zshcompsys(1) BINDABLE COMMANDS
So, we can get the most recent file with typing CTRL-x-m. For example:
% less ;# typing `CTRL-X m` here, we could get:
% less newest-file-or-directory
And we could specify some patterns here, so for example:
% less *.log ;# when I want the newest *.log:
% less newest.log
It is necessary to have some autoload -Uz compinit; compinit in the ~/.zshrc though.
You want a zsh global alias
alias -g latest='*(om[1])'
less latest

How can I implement the command 'ls' with wildcard, '*'?

EDIT #1 : I'm under the limit that all arguments are enclosed in two quotes, so that shell do not expand any argument with * to the corresponding path.
EDIT #2 : In order to retrieve directories such as */*, ../*, and dirA/*/file.out, How should I use iteration loop or recursive call?
I have just learned about the function fnmatch(). But I don't know start place.
There are many possible cases. I'm confused dealing with these all cases.
For example, Let me assume that executable program is a.out.
$./a.out -l */*
$./a.out -l ../*
$./a.out -l [file_name] [directory_name]
/* Since I also have to implement ls command with no wildcard. */
What should I do? Any advice would be awesome.
Thank you in advance.
Your problem is : shell replaces wildcard caracter * with all of the filenames matching the pattern.
Solution:
If you do not want to use this feature of bash, just put quotation marks around your command line arguments.
Calling your program that way will have the original arguments, containing wildcards.
After this, you can list all the filenames with their paths. For example using some recursive algorithm. Then you can apply some matching to these path string. (when visiting it)
If you want to be a good unix citizen, the rule is Don't do filename globbing unless you are writing a shell.
You want to write an ls-like program? Don't do any wildcard expansion. Don't treat "*" specially. Just treat your argv as a list of filenames. If your program handles these cases:
./a.out file1
./a.out file1 file2 file3
Then it will also handle
./a.out file*
correctly because the shell will do the expansion and your program won't need to know about it. And besides that, it will handle this:
zsh% ./a.out **/file<40-185>~file<90-100>(.mm-30OL[1,2])
which in zsh expanded glob syntax means: expand file40 through file185, except for file90 through file100, include only the ones that have been modified in the last 30 minutes, and use only the largest 2 files in the resulting set.
fnmatch is never going to do anything like that. But these fancy globs can be used with any command that just takes a filename list and doesn't care where it came from.
When you're in a situation where you can't take a list of filenames from the command line, then consider using fnmatch. ls isn't one of those situations.

Resources