2

I have extracted a .zip file which was generated in Windows.

Now I have a list of files like:

fileonrootfolder.txt
otherfileonrootfolder.txt
folder1\
folder1\filex.xyz
folder1\filey.xyz
folder1\filez.xyz
folder2\filex.xyz
folder2\filey.abc
....

Here the backslash \ is a part of the filename. The files are all stored in the same root folder. (As all know here, Linux uses a slash not a backslash as folder separator)

Please provide a bash command to generate the correct folder structure and move the files accordingly. (The folder hierarchy just consists of one level).

Thanks.

Additional info:

$ lsb_release -a 
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 23.10
Release:    23.10
Codename:   mantic
$ uname -a
Linux abc 6.5.0-13-generic #13-Ubuntu SMP PREEMPT_DYNAMIC Fri Nov  3 12:16:05 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
4
  • I don't know which tool you have used to "unzip" the files, but the Linux tools will create the folder structure correctly without the backslash problem. Please, retry with an Ubuntu tool like the unzip command line or the Gnome Archive Manager GUI. What is the version of your Ubuntu system? Please edit your question to add more details.
    – FedKad
    Dec 3, 2023 at 11:56
  • @FedKad. I have tried (1) using right click "Extract File" in the Ubuntu folder view, AND (2) the 'unzip compressed.zip' command from the bash. Both with the same result. Seems to be a feature of the .zip file.
    – BerndGit
    Dec 3, 2023 at 12:03
  • 1
    Please, see this: unix.stackexchange.com/questions/377986/…
    – FedKad
    Dec 3, 2023 at 12:07
  • Thanks @FedKad solution at your given link worked.
    – BerndGit
    Dec 3, 2023 at 12:21

2 Answers 2

2

I don't really understand how this happened, but if you really have file names containing literal backslashes, this should convert them to the expected directory structure:

for file in *\\*; do 
  newName=${file/\\/\/}
  if [[ "$file" =~ \\$ ]]; then 
    mkdir -p "$newName" && 
      rm "$file"
  else 
    mkdir -p "$(dirname "$newName")"
    mv -- "$file" "$newName"
  fi
done

Explanation

  • for file in *\\*: The glob *\\* matches any file or directory name in the current directory whose name contains a \. Because the \ is also the escape character, we need to escape it so it is treated as a literal. That's why we can't just use *\*.

    Then, this will iterate over all files and directories whose name contains a \, saving each of them as $file.

  • newName=${file/\\/\/}: This will print the current file name with all \ replaced with /. The escaping \\ and \/) is needed since both \ and / are special characters.

  • if [[ "$file" =~ \\$ ]]; then: if this file ends with a \ , so if it is supposed to be a directory.

  • mkdir -p "$newName" && rm "$file": create the directory and delete the file.

  • else mkdir -p "$(dirname "$newName")": if it isn't a directory, create the parent directory

  • mv -- "$file" "$newName": and move the file into it.

0

Based on hint of @FedKad I could use solution from: https://unix.stackexchange.com/questions/377986/looking-for-a-script-to-convert-a-filename-with-backslashes-into-a-directory-str

for file in *\\*; do 
    dir="$(dirname -- "${file//\\/\/}")"
    filename="${file##*\\}"
    mkdir -p -- "$dir"
    mv -- "$file" "$dir"/"$filename"
done
3
  • 1
    This doesn't actually work in your case, sorry. It will leave you with folder1\ and folder2\ files. The question I answered on Unix and Linux didn't have such files.
    – terdon
    Dec 3, 2023 at 12:29
  • Yes @terdon this is correct. I have manually deleted these 'folder?\' files. Not perfect solution. But was sufficient for my job.
    – BerndGit
    Dec 3, 2023 at 12:30
  • I posted a solution that handles this, but the easiest thing is to just run `rm *\` after running what is in your answer.
    – terdon
    Dec 3, 2023 at 12:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .