My requirement is to list all files in a directory, except files ending with a ~ (backup files).

I tried to use command:

ls -l | grep -v ~    

I get this output:

asdasad
asdasad~
file_names.txt
normaltest.txt
target_filename
testshell1.sh
testshell1.sh~
testshell2.sh
testshell2.sh~
testtwo.txt
testtwo.txt~
test.txt
test.txt~

I want to get only these files:

asdasad
file_names.txt
normaltest.txt
target_filename
testshell1.sh
testshell2.sh
testtwo.txt
test.txt
  • It looks like you are trying to avoid listing files that end with a ~. These file are backup files created my some text editors. – ctrl-alt-delor Sep 26 at 15:17
  • Which operating system are you using: is it a Gnu/Linux (such as Debian, Ubuntu, Redhat, Centos, Fedora, Suse, Mint, Arch, …)? – ctrl-alt-delor Sep 26 at 15:23
  • 2
    Note that the file you want to ignore seem to be Emacs backup files. It's rather easy to change Emacs behaviour so that it saves backups in a centralized directory and not all over the place; see emacs.stackexchange.com/questions/33/… – Kilian Foth Sep 27 at 8:55
  • I'm sorry to be mean but I don't believe you; ls -l (letter ell) would include the permissions, nlinks, owner, size and modtime for each file listed. What would produce the output you show is ls -1 (digit one) and on many systems -1 is needed to produce single-column output on the terminal, but when ls is piped (as here to grep) or redirected, -1 is not needed, it is already single-column. – dave_thompson_085 Sep 30 at 2:53
  • @dave_thompson_085 I have truncated all the text, and only file names here.. Because i felt that is irrelevant. And also this is a production system(not my own system). So i dont want to list usernames, details and leak them. – curious_one Oct 10 at 4:58
ls -l | grep -v ~

The reason this doesn't work is that the tilde gets expanded to your home directory, so grep never sees a literal tilde. (See e.g. Bash's manual on Tilde Expansion.) You need to quote it to prevent the expansion, i.e.

ls -l | grep -v "~"

Of course, this will still remove any output lines with a tilde anywhere, even in the middle of a file name or elsewhere in the ls output (though it's probably not likely to appear in usernames, dates or such). If you really only want to ignore files that end with a tilde, you can use

ls -l | grep -v "~$"

The GNU implementation of ls (found on most Linux systems) has an option for that: -B Ignore backups:

ls --ignore-backups

If you're using bash, make sure extglob is enabled:

shopt -s extglob

Then you can use:

ls -d -- !(*~)
  • -d to not show directories' contents
  • !(*~) all files except the ones ending with ~

On zsh, you can do the same with the kshglob option or using its own extended globs:

setopt extended_glob
ls -d -- ^*~

But the general idea is to use ls --ignore-backups.

This should help:

ls -l | grep -v '~'  

Reason: The ~ char is replaced by your home directory before the command is executed. Try

echo ~

and

echo '~'

As mentioned in other replies the reason you're likely having problems is because you didn't quote or escape the tilde.

For one particular use case I've used shell filename expansion to do something similar. I've been using it since about 2003, which means it has worked on a very wide variety of shell implementations on different kinds of systems. (here I also use -C because I want a nice display in sorted columns)

ls -C *[!~]

(a limitation with using shell filename expansion is of course is that a directory with very large number of (non-backup) files will cause the expansion to exceed the available argument list size, though on most modern systems this limit is quite high, often 250KB or more, sometimes much more)

ls | grep -v '~$' is the quick solution. It uses ls to list all (non-hidden) files, then uses grep with -v (inverted matching, i.e., exclusion) to exclude all lines with the tilde (~) at the end ($).

HOWEVER, if you have ANY files named like something1, something2, it's a HUGE smelly indicator that you have a bad workflow, which you should fix at the source, not with clunky hacks like modifying how ls works.

If you find yourself naming files with version numbers, like test1 and test2 or testone and testtwo, then what you really want is a version control system, like git.

This is especially true in your case, where you have multiple versions of multiple files, and the versioning seems to need to be coordinated between all of the files.

Version control systems let you essentially overlay a time window onto the filesystem, so you only see the one test file, but under the hood (through the version control program) all versions are available to search through, retrieve, revert to, compare with, etc.

Once you have this set up, you no longer need backup files from your editor, because version control has the history of the files since you started using it, even if you've made a thousand changes since then. You can even "branch" the history timeline, trying out a new idea, and going back in time and then forward to try a different idea, if you need to.

Though many answers are correct (I like the @Foon's one in particular), I'd note that getting the list of names with ls -l is a bit lame for various reasons.

The proper tool to find files is, unsurprisingly, find.

One of its upshots is that it's able to handle "selection logic" by itself, for example:

$ find . -maxdepth 1 \( -type f -a \! -name '*~' \) -print

which literally says find to:

  1. Look for files in the current directory: .
  2. Only look for them on the level of that directory—that is, do not recurse: -maxdepth 1
  3. There, look for entities, which

    • of type file: -type f
    • and: -a
    • whose names do not end in ~: ! -name *~ (where the ! negates the following directive which matches on the file names, -name *~).

    (To make the whole match on type and name appear as a logical unit, it's parenthesized with ( and )).

  4. Print the name of each file found: -print.

You need to protect some characters which are special to the shell from being interpreted by the shell, and that's why the parentheses and the bang, !, are backslash-escaped, and the name pattern, *~, is surrounded with single quotes.

The find command possess a very powerful mini-language through the usage of its options. For instance, it may be told to recursively process a whole filesystem tree (or trees) but omit certain directories while scanning. It's possible to match on several attributes of the files—such as creation or modification time or size of whatever.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.