Question

I don't expected that this will be a problem. Because I thought the coreutils support these things and then, that a dirty combination of cp ls and rm would be enough.

However, this was not the case and I would be really much appreciated if you now explain me why my approuch is failing and further, how I should do this in a proper way.

Code

function CheckoutFolder {
    local dir=$1


    mkdir "$dir/.CheckoutFolderTmp"
    (
        cd "$dir" \
        && cp -R $(ls -Q -A "$dir" --ignore=".CheckoutFolderTmp") "$dir/.CheckoutFolderTmp" \
        && rm -Rf  $(ls -Q -A "$dir" --ignore=".CheckoutFolderTmp")
    )
    mv "$dir/.CheckoutFolderTmp" "$dir/src"
    mkdir -p "$dir/"{build,log}
}

Sample output

++ CheckoutFolder /home/tobias/Develop/src/thelegacy/RCMeta
++ local dir=/home/tobias/Develop/src/thelegacy/RCMeta
++ mkdir /home/tobias/Develop/src/thelegacy/RCMeta/.CheckoutFolderTmp
++ cd /home/tobias/Develop/src/thelegacy/RCMeta
+++ ls -Q -A /home/tobias/Develop/src/thelegacy/RCMeta --ignore=.CheckoutFolderTmp
++ cp -R '"build"' '"buildmythli.sh"' '"CMakeLists.txt"' '".directory"' '".libbuildmythli.sh"' '"log"' '"RCMeta"' '"RCMetaTest"' '"src"' /home/tobias/Develop/src/thelegacy/RC
cp: cannot stat `"build"': No such file or directory
cp: cannot stat `"buildmythli.sh"': No such file or directory
cp: cannot stat `"CMakeLists.txt"': No such file or directory
cp: cannot stat `".directory"': No such file or directory
cp: cannot stat `".libbuildmythli.sh"': No such file or directory
cp: cannot stat `"log"': No such file or directory
cp: cannot stat `"RCMeta"': No such file or directory
cp: cannot stat `"RCMetaTest"': No such file or directory
cp: cannot stat `"src"': No such file or directory
++ mv /home/tobias/Develop/src/thelegacy/RCMeta/.CheckoutFolderTmp /home/tobias/Develop/src/thelegacy/RCMeta/src
++ mkdir -p /home/tobias/Develop/src/thelegacy/RCMeta/build /home/tobias/Develop/src/thelegacy/RCMeta/log
++ return 0

Mythli

Was it helpful?

Solution

As Les says, ls -Q is putting quotation-marks around the filenames, and those quotation-marks are getting passed in the arguments to cp and rm. (The use of quotation-marks to quote and delimit arguments is an aspect of the Bash command-line, when you actually type in a command; it doesn't work when you're passing the output of one command into another.) In general, parsing the output of ls is not generally a good idea.

Here is an alternative approach:

function CheckoutFolder() (
    cd "$1"

    mkdir .CheckoutFolderTmp

    find -mindepth 1 -maxdepth 1 -not -name .CheckoutFolderTmp \
         -exec mv {} .CheckoutFolderTmp/{} \;

    mv .CheckoutFolderTmp src

    mkdir build log
)

(Note that I surrounded the function body with parentheses (...) rather than curly-brackets {...}. This causes the whole function to be run in a subshell.)

OTHER TIPS

The $(ls ...) command is putting unwanted quotes around the names. Consider using xargs and back-quotes instead. For example...

(cd "$dir" && cp -R `ls -Q -A "$dir" --ignore=".CheckoutFolderTmp"` "$dir/.CheckoutFolderTmp" && ls -Q -A "$dir" --ignore=".CheckoutFolderTmp" | xargs rm -Rf  )

The cp output is not too friendly, but it does give the information you need.

cp:  cannot stat '"build"': No such file or directory

Skip to the final statement "no such file or directory". The "cannot stat" cryptic, but it means that "cp" used "stat" to get some information about the file or directory it was trying to copy. "stat" failed. It failed with the errno for "no such file or directory" on a file (or directory) named '"build"'. That's because, the actual argument internal to cp is "build" (notice) the quotes), while the file name you want is build (notice no quotes).

The $(ls... ) is called with -Q to put quotes on (presumably to handle file names with spaces and commas and other offending characters). But the $(ls...) already puts quotes on for you. xargs can also handle funky filenames if you use -0.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top