71

I wrote a shell script like this:

#! /bin/sh
...
ls | grep "android"
...

and the output is :

android1 
android2
xx_android
...

I want to add a number in each file, like this:

    1 android1 
    2 android2
    3 XX_android
    ...
    please choose your dir number:

and then wait for the user input line number x, the script reads the line number back then process the corresponding dir. How can we do this in shell ? Thanks !

BLaZuRE
  • 2,356
  • 2
  • 26
  • 43
Yifan Zhang
  • 1,461
  • 3
  • 12
  • 19
  • you can find also answer here: http://superuser.com/questions/10201/how-can-i-prepend-a-line-number-and-tab-to-each-line-of-a-text-file \ – test30 Feb 04 '16 at 13:06
  • 2
    This is just a terrible question. The correct answer to the headline is the highest voted answer... while the real problem the asker had is answered by an incorrect answer to the stated question. I don't see how it can be fixed. – Douglas Held Mar 27 '17 at 10:05
  • I recommend using a solution like https://github.com/junegunn/fzf which already has this kind of functionality built in. – km6zla Jun 26 '17 at 19:08

6 Answers6

229

nl prints line numbers:

ls | grep android | nl
Linus Kleen
  • 33,871
  • 11
  • 91
  • 99
Traz
  • 2,291
  • 2
  • 12
  • 2
  • 10
    wow, I never knew `nl` existed. that was just what I was looking for. – Keltari Oct 04 '15 at 06:43
  • 8
    On my system, this does not number empty lines (which seems to be irrelevant for the application here). Use `nl -b a` to number all lines. – krlmlr Jan 19 '16 at 11:44
  • 7
    @krlmlr: on systems without "nl", one could also use : `grep -n '^'` #^ always exist even on an empty line, so it numbers every lines. So for the OP: it could be done by `ls | grep "android" | grep -n '^'` – Olivier Dulac Dec 20 '16 at 11:00
  • 1
    nl -nrz -w2 pads numbers with zeroes to final lenght of 2 chars – andrej Jun 21 '17 at 09:20
44

If you pipe the result into cat, you can use the -n option to number each line like so:

ls | grep "android" | cat -n
Karl Barker
  • 11,095
  • 3
  • 21
  • 26
15

Pass -n to grep, as follows:

ls | grep -n "android"

From the grep man-page:

 -n, --line-number
        Prefix each line of output with the line number within its input file.
jweyrich
  • 31,198
  • 5
  • 66
  • 97
  • sorry, my question is not clear. I want to read the line number back in shell script, process the corresponding dir in shell, so just print the line number seems not work. – Yifan Zhang Feb 25 '12 at 12:03
  • 1
    You can store the command output in a variable and process it. E.g.: `RESULT=$(/bin/ls | /usr/bin/grep -n "android")` – jweyrich Feb 25 '12 at 12:06
  • yeah, but i find -n print the original line number dir, not starting from 1, is that possible to make it start from 1 ? – Yifan Zhang Feb 25 '12 at 12:10
  • @YifanZhang: You should update your question to clarify. This might help you get better answers. – jweyrich Feb 25 '12 at 12:24
  • the grep -n is great and added : serves well as stop char for following sed filters. Thanks a lot! – andrej Jun 21 '17 at 09:12
13

Instead of implementing the interaction, you can use built-in command select.

select d in $(find . -type d -name '*android*'); do
    if [ -n "$d" ]; then
        # put your command here
        echo "$d selected"
    fi
done
kev
  • 155,172
  • 47
  • 273
  • 272
  • 9
    Interesting: This question was the top hit for "linux add line numbers to output", and I didn't see how this answer helped me. The issue is that the question was *actually* an X/Y problem - and you answered the Y (whereas I really *did* need an answer to X). – Martin Bonner supports Monica Jan 27 '17 at 11:10
  • 3
    I found the real problem after reading the whole question. And solved the problem. I'm sorry the search engine didn't discover that. – kev Jan 28 '17 at 13:59
  • @MartinBonner No, this is an X problem / Y user-error. X problem was asked (don't skim the question), you're looking for Y problem based on title, this answer answered X. – BLaZuRE Aug 25 '17 at 17:56
2

The other answers on this page actually don't answer the question 100%. They don't show how to let the user interactively choose the file from another script.

The following approach will allow you to do this, as can be seen in the example. Note that the select_from_list script was pulled from this stackoverflow post

$ ls 
android1        android4        android7        mac2            mac5
android2        android5        demo.sh         mac3            mac6
android3        android6        mac1            mac4            mac7

$ ./demo.sh
1) android1  3) android3  5) android5  7) android7
2) android2  4) android4  6) android6  8) Quit
Please select an item: 3
Contents of file selected by user: 2.3 Android 1.5 Cupcake (API 3)

Here's the demo.sh and the script it uses to select an item from a list, select_from_list.sh

demo.sh

#!/usr/bin/env bash

# Ask the user to pick a file, and 
# cat the file contents if they select a file.
OUTPUT=$(\ls | grep android | select_from_list.sh | xargs cat)
STATUS=$? 

# Check if user selected something
if [ $STATUS == 0 ]
then
  echo "Contents of file selected by user: $OUTPUT"
else
  echo "Cancelled!"
fi

select_from_list.sh

#!/usr/bin/env bash

prompt="Please select an item:"

options=()

if [ -z "$1" ]
then
  # Get options from PIPE
  input=$(cat /dev/stdin)
  while read -r line; do
    options+=("$line")
  done <<< "$input"
else
  # Get options from command line
  for var in "$@" 
  do
    options+=("$var") 
  done
fi

# Close stdin
0<&-
# open /dev/tty as stdin
exec 0</dev/tty

PS3="$prompt "
select opt in "${options[@]}" "Quit" ; do 
    if (( REPLY == 1 + ${#options[@]} )) ; then
        exit 1

    elif (( REPLY > 0 && REPLY <= ${#options[@]} )) ; then
        break

    else
        echo "Invalid option. Try another one."
    fi
done    
echo $opt
Community
  • 1
  • 1
Brad Parks
  • 66,836
  • 64
  • 257
  • 336
0

This works for me:

line-number=$(ls | grep -n "android" | cut -d: -f 1)

I use this in a script to remove sections of my sitemap.xml which I don't want Googlebot to crawl. I search for the URL (which is unique) and then find the line number using the above. Using simple maths the script then calculates the range of numbers required to delete the entire entry in the XML file.

I agree with jweyrich regarding updating your question to get better answers.

Jon Lin
  • 142,182
  • 29
  • 220
  • 220