9

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?

4

5 Answers 5

40

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

ls -1 -- *.tar.gz
5
  • 1
    Why the double dashes? ls -1 *.tar.gz works just as well.
    – RonJohn
    Nov 28, 2018 at 19:50
  • 8
    @RonJohn it avoids surprises with filenames starting with -. Nov 28, 2018 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, 2018 at 22:02
  • I'm utterly disppointed that there is no -2 (or -3 etc.)! ;-) Nov 29, 2018 at 10:50
  • 1
    (... which made me look up columns!) Nov 29, 2018 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
2
  • 6
    See also ls -b, ls -Q, ls --quoting-style=.... Nov 27, 2018 at 17:10
  • And printf '%q\n'. (Both GNU.) Nov 29, 2018 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
2
  • Why -printf '%P\n' rather than just -print - at which point any Posix compatible find will work. Nov 29, 2018 at 14:18
  • @MartinBonner because -print will add ./ before the filename. Nov 29, 2018 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
  • 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, 2018 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, 2018 at 20:57
  • 3
    sorry! rm -- '-e \a.tar.gz' should do the trick
    – Jeff Schaller
    Nov 27, 2018 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, 2018 at 21:02
  • @JeffSchaller: the other solution for local names is rm_etc './-x blah' Nov 29, 2018 at 12:23

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.