8

I am trying to list every .tar.gz file, only using the following command:

ls *.tar.gz -l

...It shows me the following list:

-rw-rw-r-- 1 osm osm  949 Nov 27 16:17 file1.tar.gz
-rw-rw-r-- 1 osm osm  949 Nov 27 16:17 file2.tar.gz

However, I just need to list it this way:

file1.tar.gz 
file2.tar.gz

and also not:

file1.tar.gz file2.tar.gz

How is this "properly" done?

39

The -1 option (the digit “one”, not lower-case “L”) will list one file per line with no other information:

ls -1 -- *.tar.gz
  • 1
    Why the double dashes? ls -1 *.tar.gz works just as well. – RonJohn Nov 28 '18 at 19:50
  • 8
    @RonJohn it avoids surprises with filenames starting with -. – Stephen Kitt Nov 28 '18 at 19:54
  • 5
    Specifically... Say I was an attacker, and had the following files: .hiddenfile, benign.php, evil.bin, --hide=*evil*; without the -- you won't see evil.bin or --hide=*evil*. – wizzwizz4 Nov 28 '18 at 22:02
  • I'm utterly disppointed that there is no -2 (or -3 etc.)! ;-) – Peter A. Schneider Nov 29 '18 at 10:50
  • 1
    (... which made me look up columns!) – Peter A. Schneider Nov 29 '18 at 10:56
19

If you only need the filenames, you could use printf:

printf '%s\n' *.tar.gz

... the shell will expand the *.tar.gz wildcard to the filenames, then printf will print them, with each followed by a newline. This output would differ a bit from that of ls in the case of filenames with newlines embedded in them:

setup

$ touch file{1,2}.tar.gz
$ touch file$'\n'3.tar.gz

ls

$ ls -1 -- *.tar.gz
file1.tar.gz
file2.tar.gz
file?3.tar.gz

printf

$ printf '%s\n' *.tar.gz
file1.tar.gz
file2.tar.gz
file
3.tar.gz
  • 6
    See also ls -b, ls -Q, ls --quoting-style=.... – Stephen Kitt Nov 27 '18 at 17:10
  • And printf '%q\n'. (Both GNU.) – dave_thompson_085 Nov 29 '18 at 12:27
9

ls behaves differently when its output is piped. For example:

ls          # outputs filenames in columns
ls | cat    # passes one filename per line to the cat command

So if you want see all your *.tar.gz files, one per line, you can do this:

ls *.tar.gz | cat

But what if you don't want to pipe your output? That is, is there a way to force ls to output the filenames one to a line without piping the output?

Yes, with the -1 switch. (That's a dash with the number 1.) So you can use these commands:

ls -1             # shows all (non-hidden) files, one per line
ls -1 *.tar.gz    # shows only *.tar.gz files, one per line
7

Or with GNU find:

find  -name "*.tar.gz"  -printf '%P\n'

In contrary to ls with * it will search for .tar.gz files recursively:

$ find  -name "*.tar.gz"  -printf '%P\n'
file1.tar.gz
dir/file3.tar.gz
file2.tar.gz
  • Why -printf '%P\n' rather than just -print - at which point any Posix compatible find will work. – Martin Bonner Nov 29 '18 at 14:18
  • @MartinBonner because -print will add ./ before the filename. – Arkadiusz Drabczyk Nov 29 '18 at 14:59
4

A slightly more roundabout and loopy way:

for i in *.tar.gz; do
    echo "$i"
done

EDIT: added quotes to handle weird filenames

  • 5
    touch -- '-e \a.tar.gz' for a reason to quote your variables and unix.stackexchange.com/q/65803/117549 for reasons to use printf instead of echo – Jeff Schaller Nov 27 '18 at 20:49
  • oof, I just spent 5 minutes trying to figure out how to remove the resulting -e \a.tar.gz file – snetch Nov 27 '18 at 20:57
  • 3
    sorry! rm -- '-e \a.tar.gz' should do the trick – Jeff Schaller Nov 27 '18 at 21:01
  • You're good, it was a lesson, and I did learn that -- works for rm and a lot of others. – snetch Nov 27 '18 at 21:02
  • Thank you for that. It wouldn't be a complete question if someone didn't suggest a for-do loop to solve the problem. lol Upvoting. – Jesse Steele Nov 29 '18 at 0:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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