Zsh refer to last element of current argument list and expand it











up vote
3
down vote

favorite












Suppose I do something like:



ln a_file_with_a_long_filename.pdf ~/path/to/a/new/hardlink/a_file_with_a_long_filename_slightly_modified.pdf


Is there a way to refer to and expand a_file_with_a_long_filename.pdf if my cursor is at the end of the string ln a_file_with_a_long_filename.pdf ~/path/to/a/new/hardlink/ in zsh?



If not, what would you suggest do reduce typing work?










share|improve this question




























    up vote
    3
    down vote

    favorite












    Suppose I do something like:



    ln a_file_with_a_long_filename.pdf ~/path/to/a/new/hardlink/a_file_with_a_long_filename_slightly_modified.pdf


    Is there a way to refer to and expand a_file_with_a_long_filename.pdf if my cursor is at the end of the string ln a_file_with_a_long_filename.pdf ~/path/to/a/new/hardlink/ in zsh?



    If not, what would you suggest do reduce typing work?










    share|improve this question


























      up vote
      3
      down vote

      favorite









      up vote
      3
      down vote

      favorite











      Suppose I do something like:



      ln a_file_with_a_long_filename.pdf ~/path/to/a/new/hardlink/a_file_with_a_long_filename_slightly_modified.pdf


      Is there a way to refer to and expand a_file_with_a_long_filename.pdf if my cursor is at the end of the string ln a_file_with_a_long_filename.pdf ~/path/to/a/new/hardlink/ in zsh?



      If not, what would you suggest do reduce typing work?










      share|improve this question















      Suppose I do something like:



      ln a_file_with_a_long_filename.pdf ~/path/to/a/new/hardlink/a_file_with_a_long_filename_slightly_modified.pdf


      Is there a way to refer to and expand a_file_with_a_long_filename.pdf if my cursor is at the end of the string ln a_file_with_a_long_filename.pdf ~/path/to/a/new/hardlink/ in zsh?



      If not, what would you suggest do reduce typing work?







      zsh line-editor zle






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 2 days ago









      Gilles

      521k12610401570




      521k12610401570










      asked 2 days ago









      student

      6,8681663118




      6,8681663118






















          4 Answers
          4






          active

          oldest

          votes

















          up vote
          3
          down vote













          With the default Emacs bindings, it's just two keychords: ESC-2 ESC-^_ (i.e. Esc 2 Esc Ctrl+_ or Alt+2 Ctrl+Alt+_).
          That's the command copy-prev-word with the numeric argument 2 (the default argument 1 would copy ~/path/to/a/new/hardlink/). If the file name contains (quoted) spaces, you would need ESC-2 ESC-x copy-prev-shell-word RET. You may want to bind this command to more convenient key, especially if your keyboard layout requires Shift for _. You can use these commands in vi mode as well, but neither is bound to a key by default.



          If you get the numeric argument wrong, press Ctrl+_ to undo then try again.






          share|improve this answer




























            up vote
            1
            down vote













            This sounds like a fun code golf challenge. Here's one option:





            1. Run an innocuous command with the filename; enter enough of the filename to allow TAB-completion.



              : a_file<TAB>



            2. Use !!$ to refer to the last argument of the previous command:



              ln !!$ ~/path/to/a/new/hardlink/!!$



            Thanks to zsh's helpful quoting, this is safe even in the face of IFS-containing filenames. You'll notice that as soon as you hit space after the first !!$, zsh expands the filename; ditto if you add a gratuitous space at the end of the command.



            Number of characters required is:




            • 3 x 2 = 6 for the two !!$

            • 2 for the :<SPACE>


            8 + plus enough for the initial tab completion.






            share|improve this answer





















            • You can “golf” !!$ to ESC-., but even so this is more complicated than it should be. This isn't the 1970s anymore, shells have a line editor.
              – Gilles
              2 days ago


















            up vote
            0
            down vote













            In vi mode this would be <esc>0wyt $p which goes to command mode, 0 beginning of the line, w to the next word (advance to the filename) yt yank to space (to get the long filename, assuming no spaces in the filename) and then $p to put what was just yanked at the end of the line. This is a lot quicker than describing it once you memorize the vi motions.



            You could also setup a bindkey to yank-put the second argument though that's pretty specific code for such a use case, here bound to control+t but that could be whatever you want.



            function yank-put {
            local -a words
            words=(${(z)LBUFFER})
            if (( $#words > 1 )); then
            BUFFER+=$words[2]
            CURSOR+=${#words[2]}
            fi
            }
            zle -N yank-put
            autoload -U yank-put compinit
            compinit
            set -o vi
            bindkey -M viins "^t" yank-put





            share|improve this answer




























              up vote
              0
              down vote













              There is copy-earlier-word, you could bind it to your favorite keybinding before using it with appending these lines to ~/.zshrc:



              autoload -Uz copy-earlier-word
              zle -N copy-earlier-word
              bindkey "^[," copy-earlier-word


              So, you could use like this in the command line:



              % ln a_file_with_a_long_filename.pdf ~/path/to/a/new/hardlink/<Esc-,><Esc-,>


              (The first keypress of Esc-,(or Alt+,) yields "~/path/to/new/hardlink/" like copy-prev-shell-word, and the second time it replaces that newly inserted word with "a_file_with_a_long_filename.pdf").





              Here is a copy of copy-earlier-word document for a reference.




              This widget works like a combination of insert-last-word and copy-prev-shell-word. Repeated invocations of the widget retrieve earlier words on the relevant history line. With a numeric argument N, insert the N th word from the history line; N may be negative to count from the end of the line.



              If insert-last-word has been used to retrieve the last word on a previous history line, repeated invocations will replace that word with earlier words from the same line.



              Otherwise, the widget applies to words on the line currently being edited. The widget style can be set to the name of another widget that should be called to retrieve words. This widget must accept the same three arguments as insert-last-word.



              -- copy-earlier-word ZLE Function, widgets, zshcontrib(1)







              share|improve this answer























                Your Answer








                StackExchange.ready(function() {
                var channelOptions = {
                tags: "".split(" "),
                id: "106"
                };
                initTagRenderer("".split(" "), "".split(" "), channelOptions);

                StackExchange.using("externalEditor", function() {
                // Have to fire editor after snippets, if snippets enabled
                if (StackExchange.settings.snippets.snippetsEnabled) {
                StackExchange.using("snippets", function() {
                createEditor();
                });
                }
                else {
                createEditor();
                }
                });

                function createEditor() {
                StackExchange.prepareEditor({
                heartbeatType: 'answer',
                convertImagesToLinks: false,
                noModals: true,
                showLowRepImageUploadWarning: true,
                reputationToPostImages: null,
                bindNavPrevention: true,
                postfix: "",
                imageUploader: {
                brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                allowUrls: true
                },
                onDemand: true,
                discardSelector: ".discard-answer"
                ,immediatelyShowMarkdownHelp:true
                });


                }
                });














                 

                draft saved


                draft discarded


















                StackExchange.ready(
                function () {
                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f482827%2fzsh-refer-to-last-element-of-current-argument-list-and-expand-it%23new-answer', 'question_page');
                }
                );

                Post as a guest















                Required, but never shown

























                4 Answers
                4






                active

                oldest

                votes








                4 Answers
                4






                active

                oldest

                votes









                active

                oldest

                votes






                active

                oldest

                votes








                up vote
                3
                down vote













                With the default Emacs bindings, it's just two keychords: ESC-2 ESC-^_ (i.e. Esc 2 Esc Ctrl+_ or Alt+2 Ctrl+Alt+_).
                That's the command copy-prev-word with the numeric argument 2 (the default argument 1 would copy ~/path/to/a/new/hardlink/). If the file name contains (quoted) spaces, you would need ESC-2 ESC-x copy-prev-shell-word RET. You may want to bind this command to more convenient key, especially if your keyboard layout requires Shift for _. You can use these commands in vi mode as well, but neither is bound to a key by default.



                If you get the numeric argument wrong, press Ctrl+_ to undo then try again.






                share|improve this answer

























                  up vote
                  3
                  down vote













                  With the default Emacs bindings, it's just two keychords: ESC-2 ESC-^_ (i.e. Esc 2 Esc Ctrl+_ or Alt+2 Ctrl+Alt+_).
                  That's the command copy-prev-word with the numeric argument 2 (the default argument 1 would copy ~/path/to/a/new/hardlink/). If the file name contains (quoted) spaces, you would need ESC-2 ESC-x copy-prev-shell-word RET. You may want to bind this command to more convenient key, especially if your keyboard layout requires Shift for _. You can use these commands in vi mode as well, but neither is bound to a key by default.



                  If you get the numeric argument wrong, press Ctrl+_ to undo then try again.






                  share|improve this answer























                    up vote
                    3
                    down vote










                    up vote
                    3
                    down vote









                    With the default Emacs bindings, it's just two keychords: ESC-2 ESC-^_ (i.e. Esc 2 Esc Ctrl+_ or Alt+2 Ctrl+Alt+_).
                    That's the command copy-prev-word with the numeric argument 2 (the default argument 1 would copy ~/path/to/a/new/hardlink/). If the file name contains (quoted) spaces, you would need ESC-2 ESC-x copy-prev-shell-word RET. You may want to bind this command to more convenient key, especially if your keyboard layout requires Shift for _. You can use these commands in vi mode as well, but neither is bound to a key by default.



                    If you get the numeric argument wrong, press Ctrl+_ to undo then try again.






                    share|improve this answer












                    With the default Emacs bindings, it's just two keychords: ESC-2 ESC-^_ (i.e. Esc 2 Esc Ctrl+_ or Alt+2 Ctrl+Alt+_).
                    That's the command copy-prev-word with the numeric argument 2 (the default argument 1 would copy ~/path/to/a/new/hardlink/). If the file name contains (quoted) spaces, you would need ESC-2 ESC-x copy-prev-shell-word RET. You may want to bind this command to more convenient key, especially if your keyboard layout requires Shift for _. You can use these commands in vi mode as well, but neither is bound to a key by default.



                    If you get the numeric argument wrong, press Ctrl+_ to undo then try again.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered 2 days ago









                    Gilles

                    521k12610401570




                    521k12610401570
























                        up vote
                        1
                        down vote













                        This sounds like a fun code golf challenge. Here's one option:





                        1. Run an innocuous command with the filename; enter enough of the filename to allow TAB-completion.



                          : a_file<TAB>



                        2. Use !!$ to refer to the last argument of the previous command:



                          ln !!$ ~/path/to/a/new/hardlink/!!$



                        Thanks to zsh's helpful quoting, this is safe even in the face of IFS-containing filenames. You'll notice that as soon as you hit space after the first !!$, zsh expands the filename; ditto if you add a gratuitous space at the end of the command.



                        Number of characters required is:




                        • 3 x 2 = 6 for the two !!$

                        • 2 for the :<SPACE>


                        8 + plus enough for the initial tab completion.






                        share|improve this answer





















                        • You can “golf” !!$ to ESC-., but even so this is more complicated than it should be. This isn't the 1970s anymore, shells have a line editor.
                          – Gilles
                          2 days ago















                        up vote
                        1
                        down vote













                        This sounds like a fun code golf challenge. Here's one option:





                        1. Run an innocuous command with the filename; enter enough of the filename to allow TAB-completion.



                          : a_file<TAB>



                        2. Use !!$ to refer to the last argument of the previous command:



                          ln !!$ ~/path/to/a/new/hardlink/!!$



                        Thanks to zsh's helpful quoting, this is safe even in the face of IFS-containing filenames. You'll notice that as soon as you hit space after the first !!$, zsh expands the filename; ditto if you add a gratuitous space at the end of the command.



                        Number of characters required is:




                        • 3 x 2 = 6 for the two !!$

                        • 2 for the :<SPACE>


                        8 + plus enough for the initial tab completion.






                        share|improve this answer





















                        • You can “golf” !!$ to ESC-., but even so this is more complicated than it should be. This isn't the 1970s anymore, shells have a line editor.
                          – Gilles
                          2 days ago













                        up vote
                        1
                        down vote










                        up vote
                        1
                        down vote









                        This sounds like a fun code golf challenge. Here's one option:





                        1. Run an innocuous command with the filename; enter enough of the filename to allow TAB-completion.



                          : a_file<TAB>



                        2. Use !!$ to refer to the last argument of the previous command:



                          ln !!$ ~/path/to/a/new/hardlink/!!$



                        Thanks to zsh's helpful quoting, this is safe even in the face of IFS-containing filenames. You'll notice that as soon as you hit space after the first !!$, zsh expands the filename; ditto if you add a gratuitous space at the end of the command.



                        Number of characters required is:




                        • 3 x 2 = 6 for the two !!$

                        • 2 for the :<SPACE>


                        8 + plus enough for the initial tab completion.






                        share|improve this answer












                        This sounds like a fun code golf challenge. Here's one option:





                        1. Run an innocuous command with the filename; enter enough of the filename to allow TAB-completion.



                          : a_file<TAB>



                        2. Use !!$ to refer to the last argument of the previous command:



                          ln !!$ ~/path/to/a/new/hardlink/!!$



                        Thanks to zsh's helpful quoting, this is safe even in the face of IFS-containing filenames. You'll notice that as soon as you hit space after the first !!$, zsh expands the filename; ditto if you add a gratuitous space at the end of the command.



                        Number of characters required is:




                        • 3 x 2 = 6 for the two !!$

                        • 2 for the :<SPACE>


                        8 + plus enough for the initial tab completion.







                        share|improve this answer












                        share|improve this answer



                        share|improve this answer










                        answered 2 days ago









                        Jeff Schaller

                        36.3k952119




                        36.3k952119












                        • You can “golf” !!$ to ESC-., but even so this is more complicated than it should be. This isn't the 1970s anymore, shells have a line editor.
                          – Gilles
                          2 days ago


















                        • You can “golf” !!$ to ESC-., but even so this is more complicated than it should be. This isn't the 1970s anymore, shells have a line editor.
                          – Gilles
                          2 days ago
















                        You can “golf” !!$ to ESC-., but even so this is more complicated than it should be. This isn't the 1970s anymore, shells have a line editor.
                        – Gilles
                        2 days ago




                        You can “golf” !!$ to ESC-., but even so this is more complicated than it should be. This isn't the 1970s anymore, shells have a line editor.
                        – Gilles
                        2 days ago










                        up vote
                        0
                        down vote













                        In vi mode this would be <esc>0wyt $p which goes to command mode, 0 beginning of the line, w to the next word (advance to the filename) yt yank to space (to get the long filename, assuming no spaces in the filename) and then $p to put what was just yanked at the end of the line. This is a lot quicker than describing it once you memorize the vi motions.



                        You could also setup a bindkey to yank-put the second argument though that's pretty specific code for such a use case, here bound to control+t but that could be whatever you want.



                        function yank-put {
                        local -a words
                        words=(${(z)LBUFFER})
                        if (( $#words > 1 )); then
                        BUFFER+=$words[2]
                        CURSOR+=${#words[2]}
                        fi
                        }
                        zle -N yank-put
                        autoload -U yank-put compinit
                        compinit
                        set -o vi
                        bindkey -M viins "^t" yank-put





                        share|improve this answer

























                          up vote
                          0
                          down vote













                          In vi mode this would be <esc>0wyt $p which goes to command mode, 0 beginning of the line, w to the next word (advance to the filename) yt yank to space (to get the long filename, assuming no spaces in the filename) and then $p to put what was just yanked at the end of the line. This is a lot quicker than describing it once you memorize the vi motions.



                          You could also setup a bindkey to yank-put the second argument though that's pretty specific code for such a use case, here bound to control+t but that could be whatever you want.



                          function yank-put {
                          local -a words
                          words=(${(z)LBUFFER})
                          if (( $#words > 1 )); then
                          BUFFER+=$words[2]
                          CURSOR+=${#words[2]}
                          fi
                          }
                          zle -N yank-put
                          autoload -U yank-put compinit
                          compinit
                          set -o vi
                          bindkey -M viins "^t" yank-put





                          share|improve this answer























                            up vote
                            0
                            down vote










                            up vote
                            0
                            down vote









                            In vi mode this would be <esc>0wyt $p which goes to command mode, 0 beginning of the line, w to the next word (advance to the filename) yt yank to space (to get the long filename, assuming no spaces in the filename) and then $p to put what was just yanked at the end of the line. This is a lot quicker than describing it once you memorize the vi motions.



                            You could also setup a bindkey to yank-put the second argument though that's pretty specific code for such a use case, here bound to control+t but that could be whatever you want.



                            function yank-put {
                            local -a words
                            words=(${(z)LBUFFER})
                            if (( $#words > 1 )); then
                            BUFFER+=$words[2]
                            CURSOR+=${#words[2]}
                            fi
                            }
                            zle -N yank-put
                            autoload -U yank-put compinit
                            compinit
                            set -o vi
                            bindkey -M viins "^t" yank-put





                            share|improve this answer












                            In vi mode this would be <esc>0wyt $p which goes to command mode, 0 beginning of the line, w to the next word (advance to the filename) yt yank to space (to get the long filename, assuming no spaces in the filename) and then $p to put what was just yanked at the end of the line. This is a lot quicker than describing it once you memorize the vi motions.



                            You could also setup a bindkey to yank-put the second argument though that's pretty specific code for such a use case, here bound to control+t but that could be whatever you want.



                            function yank-put {
                            local -a words
                            words=(${(z)LBUFFER})
                            if (( $#words > 1 )); then
                            BUFFER+=$words[2]
                            CURSOR+=${#words[2]}
                            fi
                            }
                            zle -N yank-put
                            autoload -U yank-put compinit
                            compinit
                            set -o vi
                            bindkey -M viins "^t" yank-put






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered 2 days ago









                            thrig

                            23.6k12955




                            23.6k12955






















                                up vote
                                0
                                down vote













                                There is copy-earlier-word, you could bind it to your favorite keybinding before using it with appending these lines to ~/.zshrc:



                                autoload -Uz copy-earlier-word
                                zle -N copy-earlier-word
                                bindkey "^[," copy-earlier-word


                                So, you could use like this in the command line:



                                % ln a_file_with_a_long_filename.pdf ~/path/to/a/new/hardlink/<Esc-,><Esc-,>


                                (The first keypress of Esc-,(or Alt+,) yields "~/path/to/new/hardlink/" like copy-prev-shell-word, and the second time it replaces that newly inserted word with "a_file_with_a_long_filename.pdf").





                                Here is a copy of copy-earlier-word document for a reference.




                                This widget works like a combination of insert-last-word and copy-prev-shell-word. Repeated invocations of the widget retrieve earlier words on the relevant history line. With a numeric argument N, insert the N th word from the history line; N may be negative to count from the end of the line.



                                If insert-last-word has been used to retrieve the last word on a previous history line, repeated invocations will replace that word with earlier words from the same line.



                                Otherwise, the widget applies to words on the line currently being edited. The widget style can be set to the name of another widget that should be called to retrieve words. This widget must accept the same three arguments as insert-last-word.



                                -- copy-earlier-word ZLE Function, widgets, zshcontrib(1)







                                share|improve this answer



























                                  up vote
                                  0
                                  down vote













                                  There is copy-earlier-word, you could bind it to your favorite keybinding before using it with appending these lines to ~/.zshrc:



                                  autoload -Uz copy-earlier-word
                                  zle -N copy-earlier-word
                                  bindkey "^[," copy-earlier-word


                                  So, you could use like this in the command line:



                                  % ln a_file_with_a_long_filename.pdf ~/path/to/a/new/hardlink/<Esc-,><Esc-,>


                                  (The first keypress of Esc-,(or Alt+,) yields "~/path/to/new/hardlink/" like copy-prev-shell-word, and the second time it replaces that newly inserted word with "a_file_with_a_long_filename.pdf").





                                  Here is a copy of copy-earlier-word document for a reference.




                                  This widget works like a combination of insert-last-word and copy-prev-shell-word. Repeated invocations of the widget retrieve earlier words on the relevant history line. With a numeric argument N, insert the N th word from the history line; N may be negative to count from the end of the line.



                                  If insert-last-word has been used to retrieve the last word on a previous history line, repeated invocations will replace that word with earlier words from the same line.



                                  Otherwise, the widget applies to words on the line currently being edited. The widget style can be set to the name of another widget that should be called to retrieve words. This widget must accept the same three arguments as insert-last-word.



                                  -- copy-earlier-word ZLE Function, widgets, zshcontrib(1)







                                  share|improve this answer

























                                    up vote
                                    0
                                    down vote










                                    up vote
                                    0
                                    down vote









                                    There is copy-earlier-word, you could bind it to your favorite keybinding before using it with appending these lines to ~/.zshrc:



                                    autoload -Uz copy-earlier-word
                                    zle -N copy-earlier-word
                                    bindkey "^[," copy-earlier-word


                                    So, you could use like this in the command line:



                                    % ln a_file_with_a_long_filename.pdf ~/path/to/a/new/hardlink/<Esc-,><Esc-,>


                                    (The first keypress of Esc-,(or Alt+,) yields "~/path/to/new/hardlink/" like copy-prev-shell-word, and the second time it replaces that newly inserted word with "a_file_with_a_long_filename.pdf").





                                    Here is a copy of copy-earlier-word document for a reference.




                                    This widget works like a combination of insert-last-word and copy-prev-shell-word. Repeated invocations of the widget retrieve earlier words on the relevant history line. With a numeric argument N, insert the N th word from the history line; N may be negative to count from the end of the line.



                                    If insert-last-word has been used to retrieve the last word on a previous history line, repeated invocations will replace that word with earlier words from the same line.



                                    Otherwise, the widget applies to words on the line currently being edited. The widget style can be set to the name of another widget that should be called to retrieve words. This widget must accept the same three arguments as insert-last-word.



                                    -- copy-earlier-word ZLE Function, widgets, zshcontrib(1)







                                    share|improve this answer














                                    There is copy-earlier-word, you could bind it to your favorite keybinding before using it with appending these lines to ~/.zshrc:



                                    autoload -Uz copy-earlier-word
                                    zle -N copy-earlier-word
                                    bindkey "^[," copy-earlier-word


                                    So, you could use like this in the command line:



                                    % ln a_file_with_a_long_filename.pdf ~/path/to/a/new/hardlink/<Esc-,><Esc-,>


                                    (The first keypress of Esc-,(or Alt+,) yields "~/path/to/new/hardlink/" like copy-prev-shell-word, and the second time it replaces that newly inserted word with "a_file_with_a_long_filename.pdf").





                                    Here is a copy of copy-earlier-word document for a reference.




                                    This widget works like a combination of insert-last-word and copy-prev-shell-word. Repeated invocations of the widget retrieve earlier words on the relevant history line. With a numeric argument N, insert the N th word from the history line; N may be negative to count from the end of the line.



                                    If insert-last-word has been used to retrieve the last word on a previous history line, repeated invocations will replace that word with earlier words from the same line.



                                    Otherwise, the widget applies to words on the line currently being edited. The widget style can be set to the name of another widget that should be called to retrieve words. This widget must accept the same three arguments as insert-last-word.



                                    -- copy-earlier-word ZLE Function, widgets, zshcontrib(1)








                                    share|improve this answer














                                    share|improve this answer



                                    share|improve this answer








                                    edited 2 days ago

























                                    answered 2 days ago









                                    hchbaw

                                    3014




                                    3014






























                                         

                                        draft saved


                                        draft discarded



















































                                         


                                        draft saved


                                        draft discarded














                                        StackExchange.ready(
                                        function () {
                                        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f482827%2fzsh-refer-to-last-element-of-current-argument-list-and-expand-it%23new-answer', 'question_page');
                                        }
                                        );

                                        Post as a guest















                                        Required, but never shown





















































                                        Required, but never shown














                                        Required, but never shown












                                        Required, but never shown







                                        Required, but never shown

































                                        Required, but never shown














                                        Required, but never shown












                                        Required, but never shown







                                        Required, but never shown







                                        Popular posts from this blog

                                        サソリ

                                        広島県道265号伴広島線

                                        Accessing regular linux commands in Huawei's Dopra Linux