18

Is it possible to open a file from the terminal not by its name but by its (number) position in the folder? Or any other option?

Because the name is too long.

  • 5
    Please edit and give an example of what you want to do. – dessert Mar 22 at 8:50
  • 7
    No, not without coding it. But you can use "tab" completion. – Rinzwind Mar 22 at 8:51
  • 2
    Too long for what? – Carl Witthoft Mar 22 at 11:59
  • 2
    Have you tried typing the first two or three letters of the file name and then pressin the Tab key? – Henrique Mar 22 at 20:33
44

You probably haven't discovered Tab-completion (see here) yet.

While typing a filename in Terminal just type a first few letters and hit Tab and see magic!

  • 7
    Or just type the first few letters of the filename, and a *, if you don't want to use Tab-completion for some reason. Or even *abc* if the filename contains abc somewhere (try to use a subpattern that's unique to the filename you want). Or just copy/paste the filename using the mouse. – Guntram Blohm Mar 22 at 11:16
  • 4
    @guntram Or you can even drag-and-drop files to Terminal. – pomsky Mar 22 at 11:21
  • 6
    @GuntramBlohm you should make that an answer. I think it is sufficiently different from this answer to stand on its own. – KennyPeanuts Mar 22 at 15:01
32

Just for fun, literally answering the question:

enter image description here

#!/usr/bin/env python3
import os
import subprocess

show_hidden = False

currfiles = os.listdir("./")
if not show_hidden:
    currfiles = [f for f in currfiles if not f.startswith(".")]
n = 1
for f in currfiles:
    print(str(n) + ". " + f)
    n = n + 1

picked = int(input("Quick, quick, give me a number:\n"))
subprocess.run(["xdg-open", currfiles[picked - 1]])

How it works in practice

  1. In terminal, in the working dir, run "o" (as a command)
  2. The content of the current directory is listed, numbered. Pick the number and the item is opened:

    enter image description here

Set up

...is easy:

  1. Create, if it doesn't exist yet, a folder named "bin" in your home directory
  2. Copy the script into an empty file, save it as (literally) "o" (no extension), and make it executable
  3. Log out and back in and start using the command by just typing

    $ o
    

    in terminal

N.B.

If you'd like to show hidden files as well, change

show_hidden = False

into:

show_hidden = True
  • 1
    If ~/bin isn't already in your PATH, you'll have to add it (for instance, putting a line like export PATH="$PATH:~/bin" into .bashrc or .profile.) – kundor Mar 22 at 20:08
  • See b0fh's answer - this seems to be a built-in from bash – mgarciaisaia Mar 22 at 20:25
  • 1
    @kundor nope, not on Ubuntu. Log out and in does the job, or simply source ~/.profile. – Jacob Vlijm Mar 22 at 20:47
  • @JacobVlijm ~/bin is not built into anything at all. Ubuntu and Debian ship with custom ~/.profile that has lines if [ -d "$HOME/bin" ] ; then PATH="$HOME/bin:$PATH" ; fi. On Mac OS X and CentOS you have to configure that yourself. A good chance is that if Ubuntu is provided to a person by IT department, chances are the ~/.profile won't be the same as default Ubuntu, so it's a good practice to always beware that ~/bin is not standard. Bash also can ignore ~/.profile if you launch the shell with --no-profile option – Sergiy Kolodyazhnyy Mar 23 at 5:21
  • @mgarciaisaia Original comment was meant for you, actually ^ – Sergiy Kolodyazhnyy Mar 23 at 6:23
28

There is a little-known feature in Bash that allows you to do this without calling on python or any other third-party tool, and with a single line:

select file in *; do open "$file"; break; done
  • 8
    Excellent! open typically won't work, though (unless you're on Mac OS); xdg-open will probably do the trick on most GNU/Linux systems. – kundor Mar 22 at 20:11
  • 1
    But bash is not the only shell in existence, you know :-) – jamesqf Mar 23 at 5:25
16

In pure bash, using the select statement:

PS3='Quick, quick, give a number: '

select file in *
do 
    xdg-open "$file"
    break
done

Setting PS3 is just eyecandy. If you leave it out, you will just get the default prompt. If you leave out the break statement, the select statement will loop until you hit CTRL-D or CTRL-C.

Of course you can also run it as a one-liner:

select file in *; do xdg-open "$file"; break; done
  • Simple enough of a solution and works well enough. You can go a step further and make an alias or function out of it – Sergiy Kolodyazhnyy Mar 23 at 5:24
7

You can install and use mc, Midnight Commander. It is a text user interface with menus etc inspired by the old Norton Commander, that was popular when people used MSDOS (before Windows).

sudo apt update
sudo apt install mc

and start it in a terminal window or in a text screen,

mc
5

$ ls

results.log
string
Templates
textfile
time
time.save
vegetables
vegetablesbsh

How bout

ls | sed -n 3p

Prints 3rd file name

Templates

Open it-

xdg-open "$(ls | sed -n 3p)"

Usually works.

Put it in a script

#!/bin/bash

xdg-open "$(ls | sed -n "$1"p)"

Name of script: open

Save it in home folder. Run:

./open file_number
3

On Linux filesystems, filenames have a very interesting property called inode: a directory ( or folder ) is a listing of inodes and which filenames point to those inodes. So, if you know the inode number, you can attempt to locate the file using find utility and do certain operations on it. This is especially useful when dealing with filenames in different locale, special characters, or when you accidentally created directory called ~.

For example,

$ ls -i1
1103993 crs.py
1103743 foobar.txt
1147196 __pycache__
1103739 'with'$'\n''newline.png'
1103740 yellowstone.jpg

$ find . -type f -inum 1103743 -exec xdg-open {} \; -and -quit

What this does is traverse current working directory ( represented by . ) and look for directory entry that is a file with inode number 1103743. If the file is found, xdg-open will open the file with default application and find will quit afterwards. The reason for the extra -and and -quit is to prevent xdg-open reopening the file if there exist hard links to the file (which is equivalent to opening the same file twice).

1

Make some files:

$ for i in $(seq -w 0 20); do echo "This is file $i." > $i.txt; done
$ ls
00.txt  03.txt  06.txt  09.txt  12.txt  15.txt  18.txt
01.txt  04.txt  07.txt  10.txt  13.txt  16.txt  19.txt
02.txt  05.txt  08.txt  11.txt  14.txt  17.txt  20.txt
$ cat 16.txt 
This is file 16.

Put the files into a variable and open the file by an index.

$ files=(*)
$ xdg-open "${files[12]}"
# Opens 12.txt in a text editor, which reads "This is file 12."

Replace 12 with the index you're trying to open.

  • I'd prefer {00..20} instead of $(seq -w 0 20) because it's just one external process less to spawn. I'm not sure about portability though. Might be a bash-ism.. ;-) – Oscar Mar 25 at 15:38
0

This is probably the simplest answer that directly answers the question. try the following:

touch file-1 file-2 file-3

Let's say we want to open (or edit) the second file, we can do the following:

echo `ls` | cut -d' ' -f2

this will output the name of the second file, which we can use as input to the command we want to perform, for example:

cat $( echo `ls` | cut -d' ' -f2 )

will output the content of the second file.

note that you can change the order in which the files are printed by ls, by tweaking ls arguments, see man ls for details.

[UPDATE] this assumes that you have no white-spaces in file names,
thanks @wjandrea for your observation.

  • 2
    This will fail for filenames that contain spaces. This answer gets around that, but it's still a bad idea to parse ls. Also backticks are deprecated. Use $() instead. – wjandrea Mar 24 at 1:27

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.