GNU 'ls' command not outputing the same over a pipe [duplicate] - shell

This question already has answers here:
Why does ls give different output when piped
(3 answers)
Closed 6 years ago.
When I execute the command ls on my system, I get the following output:
System:~ user# ls
asd goodfile testfile this is a test file
However, when I pipe ls to another program (such as cat or gawk), the following is output:
System:~ user# ls | cat
asd
goodfile
testfile
this is a test file
How do I get ls to read the terminal size and output the same over a pipe as it does when printing directly to the terminal?
This question has been solved.
Since I'm using bash, I used the following to achieve the desired output:
System:~ user# ls -C -w "$(tput cols)" | cat

Use ls -C to get columnar output again.
When ls detects that its output isn't a terminal, it assumes that its output is being processed by some other process that wants to parse it, so it switches to -1 (one-entry-per-line) mode to make parsing easier. To make it format in columns as when it's outputting directly to a terminal, use -C to switch back to column mode.
(Note, you may also have to use --color if you care about color output, which is also normally suppressed by outputting to a pipe.)

Maybe -x "list entries by lines instead of by columns" with possible -w "assume screen width instead of current value" is what you need.

When the output goes to a pipe or non-terminal, the output format is like ls -1. If you want the columnar output, use ls -C instead.
The reason for the discrepancy is that it is usually easier to parse one-line-per-file output in shell scripts.

Since I'm using bash, I used the following to achieve the desired output:
System:~ user# ls -C -w "$(tput cols)" | cat

Related

How can I pipe output into another command?

I have a script located at /usr/local/bin/gq which is returned by the command whereis gq, well almost. What is actually returned is gq: /usr/local/bin/gq. But the following gives me just the filepath (with some white space)
whereis gq | cut -d ":" -f 2
What I’d like to do is be able to pipe that into cat, so I can see the contents. However the old pipe isn’t working. Any suggestions?
If you want to cat the contents of gq, then how about:
cat $(which gq)
The command which gq will result in /usr/local/bin/gq, and the cat command will act on that.

Please explain this BASH command "cat /y//.ssh/id_rsa.pub"

What does this command mean?
cat /y//.ssh/id_rsa.pub
I know that cat is a concatenate command and .ssh/id_rsa.pub is probably the target file id_rsa.pub in directory .ssh
But what is the /y// all about?
I don't know bash, well out of my comfort zone and when I try to display help, it doesn't help (me):
$ cat --help
Usage: cat [OPTION]... [FILE]...
Concatenate FILE(s) to standard output.
With no FILE, or when FILE is -, read standard input.
-A, --show-all equivalent to -vET
-b, --number-nonblank number nonempty output lines, overrides -n
-e equivalent to -vE
-E, --show-ends display $ at end of each line
-n, --number number all output lines
-s, --squeeze-blank suppress repeated empty output lines
-t equivalent to -vT
-T, --show-tabs display TAB characters as ^I
-u (ignored)
-v, --show-nonprinting use ^ and M- notation, except for LFD and TAB
--help display this help and exit
--version output version information and exit
Examples:
cat f - g Output f's contents, then standard input, then g's contents.
cat Copy standard input to standard output.
GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
Report any translation bugs to <https://translationproject.org/team/>
Full documentation <https://www.gnu.org/software/coreutils/cat>
or available locally via: info '(coreutils) cat invocation'

How to not lose color when pipe output to variable [duplicate]

If I do
$ ls -l --color=always
I get a list of files inside the directory with some nice colouring for different file types etc..
Now, I want to be able to pipe the coloured output of ls through grep to filter out some files I don't need. The key is that I still want to preserve the colouring after the grep filter.
$ ls -l --color=always | grep -E some_regex
^ I lose the colouring after grep
EDIT: I'm using headless-server Ubuntu 8.10, Bash 3.2.39, pretty much a stock install with no fancy configs
Your grep is probably removing ls's color codes because it has its own coloring turned on.
You "could" do this:
ls -l --color=always | grep --color=never pattern
However, it is very important that you understand what exactly you're grepping here. Not only is grepping ls unnecessary (use a glob instead), this particular case is grepping through not only filenames and file stats, but also through the color codes added by ls!
The real answer to your question is: Don't grep it. There is never a need to pipe ls into anything or capture its output. ls is only intended for human interpretation (eg. to look at in an interactive shell only, and for this purpose it is extremely handy, of course). As mentioned before, you can filter what files ls enumerates by using globs:
ls -l *.txt # Show all files with filenames ending with `.txt'.
ls -l !(foo).txt # Show all files with filenames that end on `.txt' but aren't `foo.txt'. (This requires `shopt -s extglob` to be on, you can put it in ~/.bashrc)
I highly recommend you read these two excellent documents on the matter:
Explanation of the badness of parsing ls: http://mywiki.wooledge.org/ParsingLs
The power of globs: http://mywiki.wooledge.org/glob
You should check if you are really using the "real" ls, just by directly calling the binary:
/bin/ls ....
Because: The code you described really should work, unless ls ignores --color=always for some weird reason or bug.
I suspect some alias or function that adds (directly or through a variable) some options. Double-check that this isn't the case.

wc output differs inside/outside vim

I'm working on a text file that contains normal text with LaTeX-style comments (lines starting with a %). To determine the non-comment word count of the file, I was running this command in Bash:
grep -v "^%" filename | wc -w
which returns about the number of words I would expect. However, if from within vim I run this command:
:r! grep -v "^%" filename | wc -w
It outputs the word count which includes the comments, but I cannot figure out why.
For example, with this file:
%This is a comment.
This is not a comment.
Running the command from outside vim returns 5, but opening the file in vim and running the similar command prints 9.
I also was having issues getting vim to prepend a "%" to the command's output, but if the output is wrong anyways, that issue becomes irrelevant.
The % character is special in vi. It gets substituted for the filename of the current file.
Try this:
:r! grep -v "^\%" filename | wc -w
Same as before but backslash-escaping the %. In my testing just now, your example :r! command printed 9 as it did for you, and the above printed 5.

Redirecting two files to standard input

There are several unix commands that are designed to operate on two files. Commonly such commands allow the contents for one of the "files" to be read from standard input by using a single dash in place of the file name.
I just came across a technique that seems to allow both files to be read from standard input:
comm -12 <(sort file1) <(sort file2)
My initial disbelieving reaction was, "That shouldn't work. Standard input will just have the concatenation of both files. The command won't be able to tell the files apart or even realize that it has been given the contents of two files."
Of course, this construction does work. I've tested it with both comm and diff using bash 3.2.51 on cygwin 1.7.7. I'm curious how and why it works:
Why does this work?
Is this a Bash extension, or is this straight Bourne shell functionality?
This works on my system, but will this technique work on other platforms? (In other words, will scripts written using this technique be portable?)
Bash, Korn shell (ksh93, anyway) and Z shell all support process substitution. These appear as files to the utility. Try this:
$ bash -c 'echo <(echo)'
/dev/fd/63
$ ksh -c 'echo <(echo)'
/dev/fd/4
$ zsh -c 'echo <(echo)'
/proc/self/fd/12
You'll see file descriptors similar to the ones shown.
This is a standard Bash extension. <(sort file1) opens a pipe with the output of the sort file1 command, gives the pipe a temporary file name, and passes that temporary file name on the comm command line.
You can see how it works by getting echo to tell you what's being passed to the program:
echo <(sort file1) <(sort file2)

Resources