Как я могу рекурсивно работать через дерево каталогов и выполнять определенную команду для каждого файла и вывести путь в путь, имя файла, расширение, размер файла и некоторый другой конкретный текст в один файл в bash.
Я немного озадачен тем, почему никто еще не опубликовал его, но действительно bash имеет рекурсивные возможности, если вы включите опцию globstar и используете ** glob. Таким образом, вы можете написать (почти) чистый скрипт bash, который использует этот рекурсивный globstar следующим образом:
#!/usr/bin/env bash
shopt -s globstar
for i in ./**/*
do
if [ -f "$i" ];
then
printf "Path: %s\n" "${i%/*}" # shortest suffix removal
printf "Filename: %s\n" "${i##*/}" # longest prefix removal
printf "Extension: %s\n" "${i##*.}"
printf "Filesize: %s\n" "$(du -b "$i" | awk '{print $1}')"
# some other command can go here
printf "\n\n"
fi
done
Обратите внимание, что здесь мы используем расширение параметра, чтобы получить нужные нам части имени файла, re, не полагаясь на внешние команды, за исключением получения размера файла с помощью du и очистки вывода с помощью awk.
И когда он пересекает ваше дерево каталогов, ваш вывод должен выглядеть примерно так:
Path: ./glibc/glibc-2.23/benchtests
Filename: sprintf-source.c
Extension: c
Filesize: 326
Применяются стандартные правила использования скрипта: убедитесь, что он выполним с chmod +x ./myscript.sh и запустил его из текущего каталога через ./myscript.sh или поместил его в ~/bin и запустил source ~/.profile.
Я немного озадачен тем, почему никто еще не опубликовал его, но действительно bash имеет рекурсивные возможности, если вы включите опцию globstar и используете ** glob. Таким образом, вы можете написать (почти) чистый скрипт bash, который использует этот рекурсивный globstar следующим образом:
#!/usr/bin/env bash
shopt -s globstar
for i in ./**/*
do
if [ -f "$i" ];
then
printf "Path: %s\n" "${i%/*}" # shortest suffix removal
printf "Filename: %s\n" "${i##*/}" # longest prefix removal
printf "Extension: %s\n" "${i##*.}"
printf "Filesize: %s\n" "$(du -b "$i" | awk '{print $1}')"
# some other command can go here
printf "\n\n"
fi
done
Обратите внимание, что здесь мы используем расширение параметра, чтобы получить нужные нам части имени файла, re, не полагаясь на внешние команды, за исключением получения размера файла с помощью du и очистки вывода с помощью awk.
И когда он пересекает ваше дерево каталогов, ваш вывод должен выглядеть примерно так:
Path: ./glibc/glibc-2.23/benchtests
Filename: sprintf-source.c
Extension: c
Filesize: 326
Применяются стандартные правила использования скрипта: убедитесь, что он выполним с chmod +x ./myscript.sh и запустил его из текущего каталога через ./myscript.sh или поместил его в ~/bin и запустил source ~/.profile.
Я немного озадачен тем, почему никто еще не опубликовал его, но действительно bash имеет рекурсивные возможности, если вы включите опцию globstar и используете ** glob. Таким образом, вы можете написать (почти) чистый скрипт bash, который использует этот рекурсивный globstar следующим образом:
#!/usr/bin/env bash
shopt -s globstar
for i in ./**/*
do
if [ -f "$i" ];
then
printf "Path: %s\n" "${i%/*}" # shortest suffix removal
printf "Filename: %s\n" "${i##*/}" # longest prefix removal
printf "Extension: %s\n" "${i##*.}"
printf "Filesize: %s\n" "$(du -b "$i" | awk '{print $1}')"
# some other command can go here
printf "\n\n"
fi
done
Обратите внимание, что здесь мы используем расширение параметра, чтобы получить нужные нам части имени файла, re, не полагаясь на внешние команды, за исключением получения размера файла с помощью du и очистки вывода с помощью awk.
И когда он пересекает ваше дерево каталогов, ваш вывод должен выглядеть примерно так:
Path: ./glibc/glibc-2.23/benchtests
Filename: sprintf-source.c
Extension: c
Filesize: 326
Применяются стандартные правила использования скрипта: убедитесь, что он выполним с chmod +x ./myscript.sh и запустил его из текущего каталога через ./myscript.sh или поместил его в ~/bin и запустил source ~/.profile.
Хотя решения find просты и мощны, я решил создать более сложное решение, основанное на этой интересной функции, которую я видел несколько дней назад.
Здесь приведены дополнительные пояснения и два других сценария, основанных на текущем.1. Создайте исполняемый файл сценария под названием walk, который находится в /usr/local/bin, чтобы быть доступным как команда оболочки:
sudo touch /usr/local/bin/walk
sudo chmod +x /usr/local/bin/walk
sudo nano /usr/local/bin/walk
Дополнительные пояснения и два других сценария, основанных на текущем, предоставляются здесь. 1. Содержание скрипта walk:
#!/bin/bash
# Colourise the output
RED='\033[0;31m' # Red
GRE='\033[0;32m' # Green
YEL='\033[1;33m' # Yellow
NCL='\033[0m' # No Color
file_specification() {
FILE_NAME="$(basename "${entry}")"
DIR="$(dirname "${entry}")"
NAME="${FILE_NAME%.*}"
EXT="${FILE_NAME##*.}"
SIZE="$(du -sh "${entry}" | cut -f1)"
printf "%*s${GRE}%s${NCL}\n" $((indent+4)) '' "${entry}"
printf "%*s\tFile name:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$FILE_NAME"
printf "%*s\tDirectory:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$DIR"
printf "%*s\tName only:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$NAME"
printf "%*s\tExtension:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$EXT"
printf "%*s\tFile size:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$SIZE"
}
walk() {
local indent="${2:-0}"
printf "\n%*s${RED}%s${NCL}\n\n" "$indent" '' "$1"
# If the entry is a file do some operations
for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
# If the entry is a directory call walk() == create recursion
for entry in "$1"/*; do [[ -d "$entry" ]] && walk "$entry" $((indent+4)); done
}
# If the path is empty use the current, otherwise convert relative to absolute; Exec walk()
[[ -z "${1}" ]] && ABS_PATH="${PWD}" || cd "${1}" && ABS_PATH="${PWD}"
walk "${ABS_PATH}"
echo
3. Объяснение:
Основной механизм функции walk() довольно хорошо описан Zanna в ее ответе. Поэтому я опишу только новую часть. Внутри функции walk() я добавил этот цикл:for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
Это означает, что для каждого $entry, который является файлом, будет выполняться функция file_specification(). Функция file_specification() состоит из двух частей. Первая часть получает данные, относящиеся к файлу - имя, путь, размер и т. Д. Вторая часть выводит данные в хорошо отформатированной форме. Для форматирования данных используется команда printf. И если вы хотите настроить скрипт, вы должны прочитать об этой команде - например, в этой статье. Функция file_specification() является хорошим местом, где вы можете поместить определенную команду, которая должна быть выполнена для каждого файла. Используйте этот формат: command "${entry}" Или вы можете сохранить вывод команды как переменную, а затем printf эту переменную и т. Д .: MY_VAR="$(command "${entry}")"
printf "%*s\tFile size:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$MY_VAR" Или непосредственно printf вывод команды: printf "%*s\tFile size:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$(command "${entry}")" Раздел в попрошайничество, называемое Colourise the output, инициализирует несколько переменных, которые используются в команде printf для обработки результата. Подробнее об этом вы можете найти здесь. В нижней части скрипта добавлено дополнительное условие, касающееся абсолютных и относительных путей. 3. Примеры использования:
Основной механизм функции walk() довольно хорошо описан Zanna в ее ответе. Поэтому я опишу только новую часть.Основной механизм функции walk() довольно хорошо описан Zanna в ее ответе. Поэтому я опишу только новую часть.
walk <directory name>
walk ./<directory name>
walk <directory name>/<sub directory>
В функции walk() я добавил этот цикл: for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
Это означает, что для каждого $entry, который является файлом, будет выполнен function file_specification(). В функции walk() я добавил этот цикл:
walk > output.file
Функция file_specification() состоит из двух частей. Первая часть получает данные, относящиеся к файлу - имя, путь, размер и т. Д. Вторая часть выводит данные в хорошо отформатированной форме. Для форматирования данных используется команда printf. И если вы хотите настроить скрипт, вы должны прочитать об этой команде - например, эту статью. Чтобы запустить walk для любого дочернего каталога:
Чтобы создать текстовый файл, основанный на выходе walk:
Вы можете использовать find для выполнения задания
find /path/ -type f -exec ls -alh {} \;
Это поможет вам, если вы просто хотите перечислить все файлы с размером.
-exec позволит вы должны выполнить пользовательскую команду или скрипт для каждого файла \;, используемого для одновременного анализа файлов, вы можете использовать +;, если хотите их конкатенировать (означает имена файлов).
Только с find.
find /path/ -type f -printf "path:%h fileName:%f size:%kKB Some Text\n" > to_single_file
Или вы можете использовать ниже:
find -type f -not -name "to_single_file" -execdir sh -c '
printf "%s %s %s %s Some Text\n" "$PWD" "${1#./}" "${1##*.}" $(stat -c %s "$1")
' _ {} \; > to_single_file
Если вы знаете, насколько глубоким является дерево, самым простым способом будет использование подстановочного знака *.
Запишите все, что вы хотите сделать в качестве сценария оболочки или функции
function thing() { ... }
, затем запустите for i in *; do thing "$i"; done, for i in */*; do thing "$i"; done, ... и т. д.
В вашей функции / скрипте вы можете использовать несколько простых тестов для выделения файлов, с которыми хотите работать, и делай все, что с ними нужно.
find может сделать это:
find ./ -type f -printf 'Size:%s\nPath:%H\nName:%f\n'
Посмотрите на man find для других свойств файла.
Если вам действительно нужно расширение, вы можете добавить это :
find ./ -type f -printf 'Size:%s\nPath:%H\nName:%f\nExtension:' -exec sh -c 'echo "${0##*.}\n"' {} \;
Если вы знаете, насколько глубоким является дерево, самым простым способом будет использование подстановочного знака *.
Запишите все, что вы хотите сделать в качестве сценария оболочки или функции
function thing() { ... }
, затем запустите for i in *; do thing "$i"; done, for i in */*; do thing "$i"; done, ... и т. д.
В вашей функции / скрипте вы можете использовать несколько простых тестов для выделения файлов, с которыми хотите работать, и делай все, что с ними нужно.
find может сделать это:
find ./ -type f -printf 'Size:%s\nPath:%H\nName:%f\n'
Посмотрите на man find для других свойств файла.
Если вам действительно нужно расширение, вы можете добавить это :
find ./ -type f -printf 'Size:%s\nPath:%H\nName:%f\nExtension:' -exec sh -c 'echo "${0##*.}\n"' {} \;
Хотя решения find просты и мощны, я решил создать более сложное решение, основанное на этой интересной функции, которую я видел несколько дней назад.
Здесь приведены дополнительные пояснения и два других сценария, основанных на текущем.1. Создайте исполняемый файл сценария под названием walk, который находится в /usr/local/bin, чтобы быть доступным как команда оболочки:
sudo touch /usr/local/bin/walk
sudo chmod +x /usr/local/bin/walk
sudo nano /usr/local/bin/walk
Дополнительные пояснения и два других сценария, основанных на текущем, предоставляются здесь. 1. Содержание скрипта walk:
#!/bin/bash
# Colourise the output
RED='\033[0;31m' # Red
GRE='\033[0;32m' # Green
YEL='\033[1;33m' # Yellow
NCL='\033[0m' # No Color
file_specification() {
FILE_NAME="$(basename "${entry}")"
DIR="$(dirname "${entry}")"
NAME="${FILE_NAME%.*}"
EXT="${FILE_NAME##*.}"
SIZE="$(du -sh "${entry}" | cut -f1)"
printf "%*s${GRE}%s${NCL}\n" $((indent+4)) '' "${entry}"
printf "%*s\tFile name:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$FILE_NAME"
printf "%*s\tDirectory:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$DIR"
printf "%*s\tName only:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$NAME"
printf "%*s\tExtension:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$EXT"
printf "%*s\tFile size:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$SIZE"
}
walk() {
local indent="${2:-0}"
printf "\n%*s${RED}%s${NCL}\n\n" "$indent" '' "$1"
# If the entry is a file do some operations
for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
# If the entry is a directory call walk() == create recursion
for entry in "$1"/*; do [[ -d "$entry" ]] && walk "$entry" $((indent+4)); done
}
# If the path is empty use the current, otherwise convert relative to absolute; Exec walk()
[[ -z "${1}" ]] && ABS_PATH="${PWD}" || cd "${1}" && ABS_PATH="${PWD}"
walk "${ABS_PATH}"
echo
3. Объяснение:
Основной механизм функции walk() довольно хорошо описан Zanna в ее ответе. Поэтому я опишу только новую часть. Внутри функции walk() я добавил этот цикл:for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
Это означает, что для каждого $entry, который является файлом, будет выполняться функция file_specification(). Функция file_specification() состоит из двух частей. Первая часть получает данные, относящиеся к файлу - имя, путь, размер и т. Д. Вторая часть выводит данные в хорошо отформатированной форме. Для форматирования данных используется команда printf. И если вы хотите настроить скрипт, вы должны прочитать об этой команде - например, в этой статье. Функция file_specification() является хорошим местом, где вы можете поместить определенную команду, которая должна быть выполнена для каждого файла. Используйте этот формат: command "${entry}" Или вы можете сохранить вывод команды как переменную, а затем printf эту переменную и т. Д .: MY_VAR="$(command "${entry}")"
printf "%*s\tFile size:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$MY_VAR" Или непосредственно printf вывод команды: printf "%*s\tFile size:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$(command "${entry}")" Раздел в попрошайничество, называемое Colourise the output, инициализирует несколько переменных, которые используются в команде printf для обработки результата. Подробнее об этом вы можете найти здесь. В нижней части скрипта добавлено дополнительное условие, касающееся абсолютных и относительных путей. 3. Примеры использования:
Основной механизм функции walk() довольно хорошо описан Zanna в ее ответе. Поэтому я опишу только новую часть.Основной механизм функции walk() довольно хорошо описан Zanna в ее ответе. Поэтому я опишу только новую часть.
walk <directory name>
walk ./<directory name>
walk <directory name>/<sub directory>
В функции walk() я добавил этот цикл: for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
Это означает, что для каждого $entry, который является файлом, будет выполнен function file_specification(). В функции walk() я добавил этот цикл:
walk > output.file
Функция file_specification() состоит из двух частей. Первая часть получает данные, относящиеся к файлу - имя, путь, размер и т. Д. Вторая часть выводит данные в хорошо отформатированной форме. Для форматирования данных используется команда printf. И если вы хотите настроить скрипт, вы должны прочитать об этой команде - например, эту статью. Чтобы запустить walk для любого дочернего каталога:
Чтобы создать текстовый файл, основанный на выходе walk:
Только с find.
find /path/ -type f -printf "path:%h fileName:%f size:%kKB Some Text\n" > to_single_file
Или вы можете использовать ниже:
find -type f -not -name "to_single_file" -execdir sh -c '
printf "%s %s %s %s Some Text\n" "$PWD" "${1#./}" "${1##*.}" $(stat -c %s "$1")
' _ {} \; > to_single_file
Если вы знаете, насколько глубоким является дерево, самым простым способом будет использование подстановочного знака *.
Запишите все, что вы хотите сделать в качестве сценария оболочки или функции
function thing() { ... }
, затем запустите for i in *; do thing "$i"; done, for i in */*; do thing "$i"; done, ... и т. д.
В вашей функции / скрипте вы можете использовать несколько простых тестов для выделения файлов, с которыми хотите работать, и делай все, что с ними нужно.
find может сделать это:
find ./ -type f -printf 'Size:%s\nPath:%H\nName:%f\n'
Посмотрите на man find для других свойств файла.
Если вам действительно нужно расширение, вы можете добавить это :
find ./ -type f -printf 'Size:%s\nPath:%H\nName:%f\nExtension:' -exec sh -c 'echo "${0##*.}\n"' {} \;
Хотя решения find просты и мощны, я решил создать более сложное решение, основанное на этой интересной функции, которую я видел несколько дней назад.
Здесь приведены дополнительные пояснения и два других сценария, основанных на текущем.1. Создайте исполняемый файл сценария под названием walk, который находится в /usr/local/bin, чтобы быть доступным как команда оболочки:
sudo touch /usr/local/bin/walk
sudo chmod +x /usr/local/bin/walk
sudo nano /usr/local/bin/walk
Дополнительные пояснения и два других сценария, основанных на текущем, предоставляются здесь. 1. Содержание скрипта walk:
#!/bin/bash
# Colourise the output
RED='\033[0;31m' # Red
GRE='\033[0;32m' # Green
YEL='\033[1;33m' # Yellow
NCL='\033[0m' # No Color
file_specification() {
FILE_NAME="$(basename "${entry}")"
DIR="$(dirname "${entry}")"
NAME="${FILE_NAME%.*}"
EXT="${FILE_NAME##*.}"
SIZE="$(du -sh "${entry}" | cut -f1)"
printf "%*s${GRE}%s${NCL}\n" $((indent+4)) '' "${entry}"
printf "%*s\tFile name:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$FILE_NAME"
printf "%*s\tDirectory:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$DIR"
printf "%*s\tName only:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$NAME"
printf "%*s\tExtension:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$EXT"
printf "%*s\tFile size:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$SIZE"
}
walk() {
local indent="${2:-0}"
printf "\n%*s${RED}%s${NCL}\n\n" "$indent" '' "$1"
# If the entry is a file do some operations
for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
# If the entry is a directory call walk() == create recursion
for entry in "$1"/*; do [[ -d "$entry" ]] && walk "$entry" $((indent+4)); done
}
# If the path is empty use the current, otherwise convert relative to absolute; Exec walk()
[[ -z "${1}" ]] && ABS_PATH="${PWD}" || cd "${1}" && ABS_PATH="${PWD}"
walk "${ABS_PATH}"
echo
3. Объяснение:
Основной механизм функции walk() довольно хорошо описан Zanna в ее ответе. Поэтому я опишу только новую часть. Внутри функции walk() я добавил этот цикл:for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
Это означает, что для каждого $entry, который является файлом, будет выполняться функция file_specification(). Функция file_specification() состоит из двух частей. Первая часть получает данные, относящиеся к файлу - имя, путь, размер и т. Д. Вторая часть выводит данные в хорошо отформатированной форме. Для форматирования данных используется команда printf. И если вы хотите настроить скрипт, вы должны прочитать об этой команде - например, в этой статье. Функция file_specification() является хорошим местом, где вы можете поместить определенную команду, которая должна быть выполнена для каждого файла. Используйте этот формат: command "${entry}" Или вы можете сохранить вывод команды как переменную, а затем printf эту переменную и т. Д .: MY_VAR="$(command "${entry}")"
printf "%*s\tFile size:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$MY_VAR" Или непосредственно printf вывод команды: printf "%*s\tFile size:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$(command "${entry}")" Раздел в попрошайничество, называемое Colourise the output, инициализирует несколько переменных, которые используются в команде printf для обработки результата. Подробнее об этом вы можете найти здесь. В нижней части скрипта добавлено дополнительное условие, касающееся абсолютных и относительных путей. 3. Примеры использования:
Основной механизм функции walk() довольно хорошо описан Zanna в ее ответе. Поэтому я опишу только новую часть.Основной механизм функции walk() довольно хорошо описан Zanna в ее ответе. Поэтому я опишу только новую часть.
walk <directory name>
walk ./<directory name>
walk <directory name>/<sub directory>
В функции walk() я добавил этот цикл: for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
Это означает, что для каждого $entry, который является файлом, будет выполнен function file_specification(). В функции walk() я добавил этот цикл:
walk > output.file
Функция file_specification() состоит из двух частей. Первая часть получает данные, относящиеся к файлу - имя, путь, размер и т. Д. Вторая часть выводит данные в хорошо отформатированной форме. Для форматирования данных используется команда printf. И если вы хотите настроить скрипт, вы должны прочитать об этой команде - например, эту статью. Чтобы запустить walk для любого дочернего каталога:
Чтобы создать текстовый файл, основанный на выходе walk:
Только с find.
find /path/ -type f -printf "path:%h fileName:%f size:%kKB Some Text\n" > to_single_file
Или вы можете использовать ниже:
find -type f -not -name "to_single_file" -execdir sh -c '
printf "%s %s %s %s Some Text\n" "$PWD" "${1#./}" "${1##*.}" $(stat -c %s "$1")
' _ {} \; > to_single_file