Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have about 10 php.ini files on my system, located all over the place, and I wanted to quickly browse through them. I tried this command:

locate php.ini | xargs vi

But vi warns me Input is not from a terminal and then the console starts getting really weird - after which I need to press :q! to quit vi and then disconnect from the ssh session and reconnect to have the console behave normally again.

I think that I sort of understand what's happening here - basically the command hasn't finished when vi started so the command maybe hasn't finished and vi doesn't think that the terminal is in normal mode.

I have no idea how to fix it. I have searched Google and also unix.stackexchange.com with poor luck.

share|improve this question
    
Same question on SU. –  jw013 Jul 31 '12 at 21:00
add comment

4 Answers

up vote 4 down vote accepted

I hate xargs, I really wish it'd just die :-)

vi $(locate php.ini)

Note: this will have issues if your file paths have spaces, but it is functionally equivalent to your command.
This next version will properly handle spaces but is a bit more complicated (newlines in file names will still break it though)

(IFS=$'\n'; vi $(locate php.ini))


Explanation:

What's happening is that programs inherit their file descriptors from the process that spawned them. xargs has its STDIN connected to the STDOUT of locate, so vi has no clue what the original STDIN really in.

share|improve this answer
1  
xargs is wonderful, one of my favourite tools - it's just not suited for use with programs that use stdin for anything other than a data feed. i like your answer and your explanation other than that, so +1 anyway :) –  cas Jul 31 '12 at 22:16
    
@CraigSanders I don't like it because it's too easy to abuse (use improperly) and end up breaking. I've never run into anything that I've absolutely had to use xargs for that couldn't be done directly with the shell (or find). However I can think of cases where it would be the best solution. So, so long as you understand what xargs is doing, how it splits up the arguments, how it runs the program, etc, and are using it properly, I'd say go for it :-P –  Patrick Jul 31 '12 at 22:23
    
it can't be beat for things like ... | awk '{print $3}' | xargs | sed -e 's/ /+/g' | bc (to add up all the values of field 3). or with sed -e 's/ /|/g' to construct a regexp. and yes, like any tool, you do need to know how to use it and what its limitations and caveats are. –  cas Jul 31 '12 at 22:29
add comment

Edit multiple php.ini within the same editor ?

Try: vim -o $(locate php.ini)

share|improve this answer
add comment

A quick way to do it is to use back-ticks (a.k.a. grave accents) to execute a command prior to another command running .

E.g.

vi `find / -type f -name 'php.ini'`

The command contained within the back-ticks will execute first. The output of the contained command is then executed by the command stated before the back-ticks.

For example, in the line above, the find / -type f -name 'php.ini' command will execute first, send output, and then vi will be executed on that output.

share|improve this answer
1  
back-ticks are too easily confused for single-quotes. use $(find ...) instead. –  cas Jul 31 '12 at 22:24
1  
guessing this will also break on spaces and/or newlines in the file names? –  cwd Aug 1 '12 at 12:08
    
This is how you execute shell commands in bash scripting. I've never had anything break on spaces or new lines in my scripts or when using it in a one liner. However, I've never tried to open multiple files in vi using this method. It's quite possible it could break on new lines or spaces, depending on how vi is reading and executing the output. –  nojak Aug 8 '12 at 6:07
add comment

This question has previously been asked on the Super User forum.

Quoting from @grawity's answer on that question:

When you invoke a program via xargs, the program's stdin (standard input) points to /dev/null. (Since xargs doesn't know the original stdin, it does the next best thing.)

Vim expects its stdin to be the same as its controlling terminal, and performs various terminal-related ioctl's on stdin directly. When done on /dev/null (or any non-tty file descriptor), those ioctls are meaningless and return ENOTTY, which gets silently ignored.

This is mentioned in the manual pages for xarg. From OSX/BSD:

-o Reopen stdin as /dev/tty in the child process before executing the command. This is useful if you want xargs to run an interactive application.

Hence, on OSX, you could use the following command:

find . -name "php.ini" | xargs -o vim

While, there is no direct switch on the GNU version, this command should work:

find . -name "php.ini" | xargs bash -c '</dev/tty vim "$@"'

The above solutions are courtesy Jaime McGuigan on SuperUser. Adding them here for any future visitors searching the site for this error.

share|improve this answer
    
+1 thanks for the -o tip. i've been using xargs for years and never noticed that....just checked the man page on my system, that's because it's not a GNU xargs feature. The man page does provide xargs sh -c 'emacs "$@" < /dev/tty' emacs as what they claim is a more flexible and portable alternative (although it's kind of funny for GNU to be prefer portability to features :). –  cas Jul 31 '12 at 22:22
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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