Сценарий для слияния файлов в нескольких вложенных каталогах символьной ссылкой

В основном я ищу сценарий для автоматизации материала (См. изображение ниже) в Ubuntu. Я думаю об использовании сценария удара, но других решений (например, Python?) также было бы превосходно.

1) Предположим, что у меня есть много реальных каталогов "Folder 1" и "Folder 2" с подпапками и файлами. Предположение, что файлы в соответствующих папках 1 и 2 имеют уникальные имена. Как я могу создать новую объединенную папку, где каждый из файлов является символьными ссылками на исходные папки?

2) Сценарий должен также предложить опцию сократить разорванные символьные связи в объединенной папке.


Причина, которую я хочу сделать, это вызвано тем, что я хотел бы улучшиться, как мой материал организован. например, "Папка 1|2" могла бы быть данными, полученными в различных хронологических моментах времени. Затем я создал бы Merged_Folder1, Merged_Folder2 и т.д. для различных проектов, не копируя большие файлы.


Править: Этот вопрос отличается от этого сообщения, поскольку я хотел бы объединить соответствующие вложенные подпапки с теми же именами. Вопрос в предыдущем сообщении просто связывает главные каталоги под источниками к цели и не может объединить вложенные подпапки. Заметьте, что в моем случае ни одна из папок не была бы символьными ссылками, только файлы являются символьными ссылками.

Edit2: Я должен был разъяснить, что хочу, чтобы код объединил произвольные уровни вложенных подпапок, не всего два уровня. Следовательно я добавил "Файл J" и "Файл I" на иллюстрации в качестве примера.

Example of how I want the folder merge to work

2
задан 1 December 2018 в 04:39

2 ответа

Я думаю, что следующий сценарий оболочки сделает то, что Вы хотите

  • Исходные папки находятся в main
  • На нескольких уровнях могут быть подпапки
  • Объединенная папка links
  • выполните основной сценарий оболочки script в каталоге, содержащем main и links

script

#!/bin/bash

mkdir -p links

find main -type d -exec bash -c \
'for pathname do
  #echo "------------------------------${pathname} ${pathname#*/*/}"
  if [ "${pathname/*\/*\/}" != "${pathname}" ]
  then
   mkdir -p "links/${pathname#*/*/}"
  fi
 done' bash {} +

find main -type f -exec bash -c \
'curdir=$(pwd)
for pathname do
  tpat=${pathname/main\/}
  ln -s "${curdir}/${pathname}" "links/${tpat#*/}" 2> /dev/null;
 done' bash {} +

find links -type l -exec bash -c \
'for pathname do
  LANG=C
  file "$pathname"|grep -o  "$pathname: broken symbolic link" > /dev/null; \
  if [ $? -eq 0 ];then rm "$pathname";fi
 done' \
 bash {} +

Демонстрация

$ \rm -r links

$ find main
main
main/f 4
main/f 4/s 4
main/f 4/s 4/k 4
main/asdf
main/f2
main/f2/s3
main/f2/s3/h
main/f2/s3/g
main/f2/s3/ss
main/f2/s3/ss/i
main/f2/s1
main/f2/s1/c
main/f2/s1/d
main/j
main/f1
main/f1/s2
main/f1/s2/x y
main/f1/s2/f
main/f1/s2/e
main/f1/s1
main/f1/s1/a
main/f1/s1/b

$ ./script  # doing it

$ find links/ -type l -exec file {} \;
links/s2/x y: symbolic link to /media/multimed-2/test/test0/matohak/main/f1/s2/x y
links/s2/f: symbolic link to /media/multimed-2/test/test0/matohak/main/f1/s2/f
links/s2/e: symbolic link to /media/multimed-2/test/test0/matohak/main/f1/s2/e
links/s3/h: symbolic link to /media/multimed-2/test/test0/matohak/main/f2/s3/h
links/s3/g: symbolic link to /media/multimed-2/test/test0/matohak/main/f2/s3/g
links/s3/ss/i: symbolic link to /media/multimed-2/test/test0/matohak/main/f2/s3/ss/i
links/s 4/k 4: symbolic link to /media/multimed-2/test/test0/matohak/main/f 4/s 4/k 4
links/asdf: symbolic link to /media/multimed-2/test/test0/matohak/main/asdf
links/s1/a: symbolic link to /media/multimed-2/test/test0/matohak/main/f1/s1/a
links/s1/c: symbolic link to /media/multimed-2/test/test0/matohak/main/f2/s1/c
links/s1/b: symbolic link to /media/multimed-2/test/test0/matohak/main/f1/s1/b
links/s1/d: symbolic link to /media/multimed-2/test/test0/matohak/main/f2/s1/d
links/j: symbolic link to /media/multimed-2/test/test0/matohak/main/j

$ ln -s main/asdf links/asdf-b  # create a broken link

$ find links/ -type l -name "asdf*" -exec file {} \;
links/asdf-b: broken symbolic link to main/asdf
links/asdf: symbolic link to /media/multimed-2/test/test0/matohak/main/asdf

$ ./script  # this time only to remove the broken link

$ find links/ -type l -name "asdf*" -exec file {} \;
links/asdf: symbolic link to /media/multimed-2/test/test0/matohak/main/asdf
$

Случай, который позволил бы Вам указывать который папка под основным /* для слияния

#!/bin/bash
# First argument is target, following arbitrary number of target folders
# eg. ./script.sh links main/f1 main/f2 main/f3

argc=$#
argv=($@)

mkdir -p ${argv[0]}

for (( j=1; j<argc; j++ )); do

    find ${argv[j]} -type d -exec bash -c \
    'for pathname do
      #echo "------------------------------${pathname} ${pathname#*/*/}"
      if [ "${pathname/*\/*\/}" != "${pathname}" ]
      then
       mkdir -p "'${argv[0]}'/${pathname#*/*/}"
      fi
     done' bash {} +

    find ${argv[j]} -type f -exec bash -c \
    'curdir=$(pwd)
    for pathname do
      tpat=${pathname/${argv[j]}\/}
      ln -s "${curdir}/${pathname}" "'${argv[0]}'/${tpat#*/}" 2> /dev/null;
     done' bash {} +

    find ${argv[0]} -type l -exec bash -c \
    'for pathname do
      LANG=C
      file "$pathname"|grep -o  "$pathname: broken symbolic link" > /dev/null; \
      if [ $? -eq 0 ];then rm "$pathname";fi
     done' \
     bash {} +

    find ${argv[0]} -type d -empty -delete  # Removes empty dir in target

done
1
ответ дан 2 December 2019 в 03:30

Получил его... этот код Python должен смочь идти через произвольное число вложенных каталогов и создать символьные ссылки для файлов все объединенные в целевой каталог. Аргументами является цель и исходные каталоги соответственно. Исходные каталоги должны быть относительно целевого dir, например.

python script.py ./merged_folder ../folder1 ../folder2 ../folder3
import os
import sys
import time
'''
Loops through merge_symlink.
See https://askubuntu.com/questions/1097502/script-for-merging-files-in-multiple-nested-directories-by-symbolic-link/
KH Tam Nov 2018 (matohak)

Use: python merge_symlink.py ./target ../folder1 ../folder2 ../folder3
Note that if overwrite==True and there are duplicated filenames, links will be overwritten by the last argument's
'''

def merge_symlink(sources, overwrite=True, remove_empty_dir=True, verbose=False):
    '''
    See https://askubuntu.com/questions/1097502/script-for-merging-files-in-multiple-nested-directories-by-symbolic-link/
    Function to be run in the target directory.

    :param sources: a list of directories where the files in the subdirectories are to be merged symbolically. Path relative to the target. eg. ["../folder1", "../folder2"]
    :param overwrite: Bool, whether to overwrite existing symbolic links
    :param remove_empty_dir: Bool, whether to remove empty directories in target.
    :param verbose: Prints stuff.
    :return: None
    '''

    # Creating symlinks and folders
    for source in sources:
        for dirName, subdirList, fileList in os.walk(source):
            # print(dirName, fileList)  # print all source dir and files
            if source[-1] == "/": source=source[:-1]

            target_dir = dirName.replace(source, '.', 1)
            depth = dirName.count("/") - source.count("/")

            try:
                os.mkdir(os.path.join(target_dir))
            except FileExistsError:
                pass

            for file in fileList:
                targetlink = os.path.join(target_dir, file)
                try:
                    os.symlink(os.path.join("../"*depth + dirName, file), targetlink)
                except FileExistsError:
                    if overwrite and not (isvalidlink(targetlink)==2):  # Never replace a real file with a symlink!
                        os.remove(targetlink)
                        os.symlink(os.path.join("../" * depth + dirName, file), targetlink)
                        if verbose: print('overwriting {}'.format(targetlink))

    # Pruning broken links and then deleting empty folders.
    for dirName, subdirList, fileList in os.walk("./"):
        for file in fileList:
            link = os.path.join(dirName,file)
            if isvalidlink(link)==0:
                os.remove(link)
                if verbose: print("Removing broken symlink: {}".format(link))

    if remove_empty_dir:
        for dirName, subdirList, fileList in os.walk("./"):
            if fileList==[] and subdirList==[] and dirName!="./":
                os.rmdir(dirName)

# Checks if file is a broken link. 0: broken link; 1: valid link; 2: not a link
def isvalidlink(path):
    if not os.path.islink(path):
        return 2
    try:
        os.stat(path)
    except os.error:
        return 0
    return 1

if __name__ == "__main__":

    target = sys.argv[1]
    sources = sys.argv[2:]      # Inputs should be relative to the target dir.
    overwrite = False
    loop = False
    looptime = 10

    os.chdir(target)
    if not loop:
        merge_symlink(sources, overwrite=overwrite)
    else:
        while loop:
            merge_symlink(sources, overwrite=overwrite)
            time.sleep(looptime)

Благодарите @JacobVlijm за ссылку и @sudodus для помощи!

1
ответ дан 2 December 2019 в 03:30

Другие вопросы по тегам:

Похожие вопросы: