Assuming a script that outputs a list of files:

$> bash someScript.sh

Now I want to have the second file-path as parameter for another command, e.g. vim. Is there a way to directly access it?

And I want to point out that I do not necessarily want to access the second file, but the next time it could be the third or the 27th. I want to be able to select that Nth line as easily as possible.

Right now I do mouse-selecting and insert by middle-clicking or type the path with tab-completion. Now I wonder if there is an easier way.

Problem with my own solution is though that I would have to edit all my scripts this way. It would be fun if there was a more general solution to this issue, that would work with any kind of command, e.g. find.



bash someScript.sh | sed -n '2 p'

will filter your output and just print the second line of it. To make that a parameter to vim:

vim "$(bash someScript.sh | sed -n '2 p')"
  • 5
    awk way: awk 'NR==2' instead of sed -n '2 p' – Benoit Jan 24 '12 at 12:43
  • 6
    As the question is tagged efficiency, better stop sed ASAP: sed -n '2{p;q}'. This avoids reading the remainder of output in vain. @Benoit, similarly for awk: awk 'NR==2{print;exit}. – manatwork Jan 24 '12 at 12:43

Use head and tail, e.g. accessing the 2nd line of an output:

bash someScript.sh | head -2 | tail -1

If being short to type is paramount and the file isn't very large:

nth_line=$(sed -n ${n}p)
nth_line=$(sed \!${n}d)

If the file is long and you're only interested in one line, use sed to print the desired line and quit, or tail to remove the previous lines and head to extract the first line of the result.

nth_line=$(sed -n -e "$n {" -e p -e q -e "}")
nth_line=$(tail -n +$n | head -n 1)

(Note that tail -n +$n skips n-1 lines, i.e. its output starts with the nth line.)

For a small number of lines, you can use the read built-in.

IFS= read -r first_line; IFS= read -r second_line

If you want to read all lines, you can put them in an array (ksh/bash/zsh only).

second_file="${lines[1]}"  # note that ksh/bash arrays start at 0

If you want to make this reusable code, put it in a function.

# Read at most MAX input lines (default: all) into the VAR array (default: ${lines[@]}).
# Usage: read_lines [VAR [MAX]]
read_lines () {
  typeset IFS=$'\n'
  if [ $# -eq 0 ]; then set lines; fi
  if [ -z "$2" ]; then eval "$1=(\$(cat))"; else eval "$1=(\$(head -n $2))"; fi

I solved it even though it's a bit hackish ;)

That's the script outputting file paths:

rm /tmp/svn_filelist_to_source /tmp/svn_filelist
svn status | egrep 'M |A ' | cut -c9- > /tmp/svn_filelist
cat /tmp/svn_filelist | while read -r path; do
  echo $path
  echo "file$counter=\"$path\"" >> /tmp/svn_filelist_to_source

Here's how I run it, which I think I'll put in an alias:

sh statusAddedAndModified.sh && source /tmp/svn_filelist_to_source

Now I can:

svn commit $file2

  • 2
    Use IFS= read -r unless you mean to strip leading and trailing whitespace (explanation). There are shorter and faster ways to grab all lines; see my answer. – Gilles Jan 24 '12 at 18:29

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.