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 often need to selectively archive a long list of files using cp -iar, or similar, and to speed up the process I would like to press just one key instead of y or n followed by ENTER on every file. In other words I want to avoid having to press ENTER as well as y or n. Of course I would happily use different keys instead of y or n.

Is there a way to do this?

share|improve this question
    
I think I may have mistaken the use of -i, need to RTFM more carefully and come back. I still want to avoid two key presses, though –  Harry Weston Apr 27 at 16:05
    
Ok Braim, thanks, but how do I do that? –  Harry Weston Apr 27 at 16:14
    
You might want to consider rsync with the --exclude or --exclude-from options. –  user17534 Apr 27 at 18:46

7 Answers 7

up vote 7 down vote accepted

I think that what you need is a file manager, like midnight commander. In mc you can select several files with insert or + and realize operations on them, like deleting, moving or copying. A full set of instructions and tips can be found in the Tutorial.

If you give it a try to pure shell commands (no gui), suppose you have file0 to file10 but wants to copy only file1 and file3:

cp file1 file3 directory/

Of course, you can use the shell to help yourself:

cp file{1,3} directory/

but what about consecutive ones? file5 through file10?

cp file{5..10} directory/

You can also use find to help, if you want something more advanced, for example:

find Downloads -name "*.cfg" -exec cp {} directory \;

will do this:

copy Downloads/file(6).cfg to directory
copy Downloads/file(7).cfg to directory
copy Downloads/file(1).cfg to directory
copy Downloads/file.cfg to directory
copy Downloads/file(2).cfg to directory
copy Downloads/file(4).cfg to directory
copy Downloads/file(3).cfg to directory
copy Downloads/file(5).cfg to directory

you can verify the files to be copied removing the -exec ... part. You can also use -exec echo cp ... in case you want to know what find will do.

share|improve this answer
    
I appreciate your help, Braiam, thanks, but I want to avoid having to classify the files, I just want to create and traverse a list and, in effect, to tick the ones to copy, archive really, and skip the rest. Finding a formula or expression to define the files as a group is really not an option. –  Harry Weston Apr 27 at 16:36
1  
@HarryWeston maybe what you need is a file manager instead. I think midnight commander might suit you. –  Braiam Apr 27 at 17:03
    
I would have liked to accept all answers, but am not allowed, so I will have to choose, and Braiam just has the edge. Also, not supposed to say thanks, but I must: many thanks for the answers, and for the time and trouble to post them. –  Harry Weston Apr 27 at 18:08

Yes you can, but it's a bit complicated.
Here I suggest you this bash script, save it to a file named mycp.sh to be put in your PATH and don't forget to chmod +x mycp.. Obviously It needs some improvement !

#!/bin/bash
[ $# -ne 2 ] && echo -en "ERROR : Need 2 parameters.\n" && exit
[ -f $1 ] && cp $1 $2
if [ -d $1 ]  
then
    mkdir -p $2
    cd $1
    find . | while read fn
    do
        if [ -f $fn ] 
        then
            read -r -n1 yesorno
            if [ "$yesorno" == "y" ] || [ "$yesorno" == "Y" ]  
            then 
                mkdir -p $2/`dirname $fn`
                cp $fn $2/`dirname $fn`
            fi
        fi
    done
fi
share|improve this answer
3  
There are multiple issues with your script which will cause it to break on file names containing spaces. Double quote every variable expansion and command substitution (also prefer $() over ``). Always use the -r option of read unless you want backslashes to be treated specially. Also, you might want to consider the rare case when file names start with a dash. Take a look at mywiki.wooledge.org, especially BashPitfalls, that site is a great resource for bash. –  nyuszika7h Apr 27 at 18:37

In such cases where I don't want to press y followed by Enter, I copy ( Ctrl+Shift+C in my terminal setup) the y + newline once from a previous line, and then paste (Ctrl+Shift+V) whenever prompted.

That is not a single key, but something I can press in one go which is good enough for me. It is possible to keep Ctrl+Shift pressed while waiting for the next prompt.

share|improve this answer
    
That does cover the "only one key" requirement, but I need to have each file presented one at a time to do that, and I mistakenly assumed that -i in cp would behave the same as in rm -r ..., so that cuts out cp, unless I have overlooked something else, too. –  Harry Weston Apr 27 at 18:13

The most robust solution is to stash the full list of files into a file, edit that one to leave out those you don't want (has the advantage that it allows to double-check the result) and then do

cp `cat /the/list/of/files` go/here
share|improve this answer
    
I like this type of solutions. It's also possible to generate a shell script and edit it, also would more often create the shell script at least on the fly to first check what would be done and then just prepend | bash. –  Pavel Šimerda Apr 27 at 18:22
5  
This will break on file names containing spaces, and possibly ones starting with a dash (although the latter is less common). xargs -I{} cp -- {} dir/ < files.txt should work with all file names except for obscure ones containing newlines in them, but they're very rare, let's hope nobody uses them! –  nyuszika7h Apr 27 at 18:43

Based on the read invocation from Slyx, here is a simple one-liner:

{ while read -r -n1 i; do echo >&2; echo $i; done } | cp -iar …

You'll have to press Ctrl+D at the end to exit the loop. So far I haven't found working magic to exit the loop when the command is done; trapping SIGCHLD doesn't seem to work as I'd have hoped. If you save this to a file called yesorno on your path, you could write that like this:

#!/bin/bash
{ while read -r -n1 i; do echo >&2; echo $i; done } | "$@"

As an alternative, you could make it a function definition in your ~/.bash_profile:

yesorno() {
  { while read -r -n1 i; do echo >&2; echo $i; done } | "$@"
}

In either case, you could then invoke it like this:

yesorno cp -iar …
share|improve this answer

This is what I did when I needed that:

Create a file e.g: "stdin.txt"

Write the content:

y

After the y you type two new lines (Enter, Return, \n)... "y\n\n"

Then I run the command: with "$ cmd < stdin.txt" like:

share|improve this answer

If you just press 'p' and then enter it will automatically answer 'y' for all remaining questions.

share|improve this answer
    
The OP doesn't want to automatically answer y for all questions. –  StvnW Apr 28 at 14:26
    
@StvnW to be fair, that wasn't exactly clarified until an edit after my original answer. –  CongaFire Apr 29 at 17:24
    
I thought this point was clear enough in the original revision, otherwise why use -i in the first place (and not just -f)? In any case, I wasn't the one that downvoted you. If you now have greater clarity about the OPs question, you could consider updating your answer (or removing it if you feel the other posts cover it thoroughly enough.) –  StvnW Apr 29 at 18:07

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.