Reshaping a bash command

hi , i got stuck reshaping this command

find /var/cache/pacman/pkg/ -type f -ctime -30 -exec sh -c 'cp "$1" "/path/to/usb/$(basename $(echo "${1}" | sed 's/:/_colon_/'))"' sh_cp {} \;

to get it run inside quotes

#!/bin/bash
xfce4-terminal -x sh -c " ... "
"$1" becomes $"1"
"${1}" becomes ???

explanation: i’m trying to find/copy/rename all packages (those containing “:” included)
to a regular usb stick (FAT) in one step without using a temporary directory to rename them.

thanks.

Bash Reference Manual

Btw… a one-liner is not always a good idea.

4 Likes

You don’t need your sub-sub-shell:

find /var/cache/pacman/pkg/ \
    -type f \
    -ctime -30 \
    -exec sh -c 'cp -v "$1" "/path/to/usb/$(basename "$1" | sed '\''s/:/_colon_/g'\'' )"' \
    sh_cp {} \;

thanks, but your suggestion does not work inside quotes.
it’s a script beginning with

#!/bin/bash
xfce4-terminal -x sh -c " find ... "

I used a lodash (_) as replacement - but in case you later want to install the packages - it would be better to use something else.

pkg_dir=/var/cache/pacman/pkg
dest_dir=/run/media/$USER/something
ls $pkg_dir | while read -r f; do cp "$pkg_dir/$f" "$dest_dir/${f//:/_}"; done

Add -u to the cp command if you only want files which is newer than or does not exist on the destination.

1 Like

why not create a .desktop file ? with exec= xfce4-terminal -e myscript.sh --hold

Maybe this looks a bit cleaner and human-readable:

#!/usr/bin/env bash

convert() { echo "$1" | sed -e 's,:,_colon_,g'; }
copypkgs()
{
    find "${1}" -type f -ctime -30 | while read line; do
        if [[ $line =~ : ]]; then
            echo " cp -v "$line" "${2}/$(basename $(convert $line))" "
        else
           echo " cp -v "$line" "${2}/$(basename $line)" "
      fi
    done
}
copypkgs "/var/cache/pacman/pkg" "/path/to/usb"
#!/usr/bin/env bash
xfce4-terminal -x /path/to/script.sh
3 Likes

thank you all for the suggestions.

does not work properly. stopps during copying.

does not copy anything.

i just wanted to know how to get the find command into a bash script beginning with xfce4-terminal -x sh -c " ". the bash reference tells me nothing.
it’s a 353 lines script using select, different operations including command prompts, some find commands to show, count , copy and move pkgs. copying the ones without “:” works with
find /var/cache/pacman/pkg/ ! -name : -type f -daystart -ctime -30 -exec cp -nupt $USB_PATH {} + ;
but i cant rename them in one step. -execdir does not work, rename + basename neither.
i googled this and found a solution in my first post and i just need a proper substitution for the “${1}” expression.

is possible ??? for no convertion to do

in one script:
to write all your command in function
export this function
and run terminal -c “function x y z”
???

or , more simple, write this function in .bashrc ?

I did not expect that you are such a DAU. I added echo for safety, so you can view the commands and check if they work correctly. And yes, an echo will not copy anything. I thought you are aware of such practice.

1 Like

missed
i copied the code into a test script, adjusted the paths and tried to run.

yes, works.

Earned ‘DAU’

1 Like

for fun ONLY, possible to use only one script sh :upside_down_face:

#!/usr/bin/env bash

function testOne(){
  echo "I run in terminal ..."
  echo "Hello: $1"
  #find /var/cache/pacman/pkg/ -type f -ctime -30 -exec sh -c 'cp "$1" "/path/to/usb/$(basename $(echo "${1}" | sed 's/:/_colon_/'))"' sh_cp {} \;
}

[[ "$1" == "run" ]] && konsole --noclose -e bash -c "/home/patrick/test1.sh exec ${@:2}"
[[ "$1" == "exec" ]] && testOne "${@:2}"

use : ./test1.sh run TOTO

I can assure you it works

So you are not here to learn but for the copy/paste solutions?

:clown_face:

First and foremost, I was not here to be insulted.
I did not ask for a function or helper script.

bye bye

  • To use double-quotes inside double-quotes you should escape them see basics of quoting. eg:

    "bla bla \"123\" blabla"
    
  • You need to protect the {} and ; from the shell because they are to be interpreted by the find command.

  • ALWAYS break-up lines and use indentations to make it readable and able to be followed to prevent errors when writing scripts !
    The computer does not care but the human does…

  • Also escape special chars if you intend to pass them instead of being interpreted right away by the current shells.

  • Avoid sub-shells unless absolutely required, you could for example rewrite:

    cp "$1" "/path/to/usb/$(basename $(echo "${1}" | sed 's/:/_colon_/'))"
    

    Like this using only bash: (will be faster and avoids forking a new process)

    decolonized_file="${1//:/_colon_}";
    cp "$1" "/path/to/usb/${decolonized_file##*/}"
    
    • I fail to understand the need for this colon conversion unless your USB filesystem can’t handle them like FAT, in which case you will have extra problems with name lengths also… :thinking:
  • Avoid mixing different shell types as much as possible, ESPECIALLY inside a single command…
    That’s why i changed your sh invocations to bash versions…

  • :warning: And last but not least:
    You pass sh_cp as FIRST argument to the shell executed by find, so you need to use $2 inside to grab the found filename.
    :point_up: :point_up_2:

You perform something inside a shell inside another shell inside yet another shell…
So you need to be very careful about used escapes that need tobe escaped themself…

Combining all the above would result in the below:
(NOT TESTED, just applied what i wrote above while posting this reply)

#!/usr/bin/env bash

xfce4-terminal \
  -x bash -c \
    "find \
      /var/cache/pacman/pkg/ \
      -type f \
      -ctime -30 \
      -exec bash -c \" \
        decolonized_file=\\\"\\\${2//:/_colon_}\\\"; \
        cp \\\"\\\$2\\\" \\\"/path/to/usb/\\\${decolonized_file##*/}\\\" \
      \" \
      sh_cp \
      '{}' \
      ';' \
    "

Conclusion don’t try to do everything in one line or command, just use sub scripts (helper scripts) to perform actions to avoid problems caused by escape errors…
Just make sure your core action works, then call that core action as a helper script, it will allow you to debug problems MUCH easier…

IMHO, for the end purpose what you try to do, i would not let find execute commands but rather use the output and perform actions upon that output using one script…
The way you are trying to perform what you actually want as a result, is like reaching to your right ear using your left arm bend behind your head…

To be honest you won’t benefit much from the knowledge and experience of others with an attitude like that, we already have the knowledge and experience, it’s up to you to stay open to all kinds of reactions to be able to learn from them…
(We are also humans and get aggravated on occasions)

Anyhow…
:vulcan_salute:

2 Likes