How to order ls command display in numerical order? - bash

I created 3 files in a directory with the following names:
11 13 9
Problem, as I created file 9 after 13 it is placed after file 13 when I do the ls command.
Do you have any idea to make the ls command sort the files in the numerical order, like this:
9 11 13

Look at the man page for ls.
From there-
-v natural sort of (version) numbers within text.
You'll find that the command ls -v does what you want.
If you want the file names on different lines then you can do ls -1v.

List with lines without columns:
ls -x
Using tr to avoid multiple lines output:
ls | tr "\n" " "
And to ensure to accurately force ascending order:
ls -v | tr "\n" " "
Some useful and essential information from linux.org about ls.

Unfortunately, ls -v on macOS and FreeBSD does not perform a natural sort on the list of files. FreeBSD ls does not support this flag at all. On macOS it can be used to
force unedited printing of non-graphic characters; this is the default when output is not to a terminal.
If you badly need the GNU extension of -v to the ls utility, you can install the GNU ls and then use alias ls=gls to use the GNU ls instead of the default ls. GNU ls usually comes with the coreutils package, so, e.g.,
On macOS: brew install coreutils
On FreeBSD: pkg install coreutils

Related

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 treat files as huge string with macos grep?

I'm using the following command on Ubuntu to list all files containing a given pattern:
for f in *; do if grep -zoPq "foo\nbar" $f; then echo $f; fi; done
But on macos, I'm geting the following error:
grep: invalid option -- z
There's no -z option to treat files as a big string with macos grep, unlike gnu grep.
Is there another option on macos grep equivalent to `-z ? If not, what alternative can I use to get the same result ?
-P (PERL regex) is only supported in gnu grep but not on BSD grep found on Mac OS.
You can either use home brew to install gnu grep or else use this equivalent awk command:
awk 'p ~ /foo$/ && /^bar/ {print FILENAME; nextfile}; {p=$0}' *
Please note that this eliminates the need to use shell for loop.
You can install pcregrep via home brew, and then use it with the -M option:
By default, each line that matches a pattern is copied to the
standard output, and if there is more than one file, the file name is
output at the start of each line, followed by a colon. However, there
are options that can change how pcregrep behaves. In particular, the
-M option makes it possible to search for patterns that span line
boundaries. What defines a line boundary is controlled by the -N
(--newline) option.
With ripgrep
rg -lU 'foo\nbar'
This will list all filenames containing foo\nbar in the current directory. -U option allows to match multiple lines. Unlike grep -z, whole file isn't read in one-shot, so this is safe to use even for larger input files.
ripgrep recursively searches by default. Use rg -lU --max-depth 1 'foo\nbar' if you don't want to search sub-directories.
However, note that by default, rigprep ignores
files and directories that match rules specified by ignore files like .gitignore
hidden files and directories
binary files
You can change that by using:
-u or --no-ignore
-uu or --no-ignore --hidden
-uuu or --no-ignore --hidden --binary
It seems you are searching for files which have the sequence foo\nbar. With GNU awk (brew install gawk), you can set the record separatorRS to this sequence and check if the record matches:
gawk 'BEGIN{RS="foo\nbar"}{exit (RT!=RS)}' file
This will try to split your files in records which are separated by the record separator RS, if so, it will terminate with exit code 0, otherwise with exit code 1. The behaviour is the same as the proposed grep
If you just want the files listed, you can do:
gawk 'BEGIN{RS="foo\nbar"}(RT==RS){print FILENAME}{nextfile}' *

Listing directories not following specific format

I have an assignment where, only using bash one-liners, I must ls the specific directories in my home directory that do not follow a specific naming schema. In my home directory, there are some directories that have the format of 3 alphabetical lower case letters followed by 3 decimal digits. However, there are other directories that don't follow this format. I must list those files and output the info to a txt file. Here are some commands I have written so far and am experimenting with:
ls /home -1 | sed [^a-z][^a-z][^a-z].[^0-9][^0-9][^0-9]
ls /home -1 "[^[a-z][a-z][a-z][0-9][0-9][0-9]]"
ls /home -1 *{[^a-z][^a-z][^a-z].[^0-9][^0-9][^0-9]}*
Also before anyone asks, I know formatting and searching through the output of the ls command is not as effective as the find command. But the assignment that I am working on dictates that I may only use these commands: ls, ps, sed, cut, paste, sort, tr, grep, awk, cat, uniq
If you can use shopt -s extglob first, then
ls -1d /home/!([a-z][a-z][a-z][0-9][0-9][0-9])
If not,
ls -1d /home/* | grep -v '/home/[a-z][a-z][a-z][0-9][0-9][0-9]$'
PLEASE read the manual pages for ls, grep, and shopt.
If you don't understand why these work, you haven't learned anything, and we're just doing your work for you...

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

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

How can I select the filename with the highest version number?

I wrote a build script and would like to be able to select the latest version of the script when it installs, e.g. the package name is package_X.X.X.tar.gz and there are multiple copies.
Is there a way to point the build command to package_Y.tar.gz? where Y=max(X.X.X)?
If the files are equal except for the version numbers, you could use something like
ls -v | tail -n 1
From the man-page of ls:
...
-v natural sort of (version) numbers within text
...
Example usage:
$ ls
package_1.5.7.9.tar.gz package_2.5.3.9.tar.gz package_4.6.1.0.tar.gz
$ ls -v | tail -n 1
package_4.6.1.0.tar.gz

Resources