Aber, was, wenn du mit einer vollkommen falschen Vorstellung der Sache gegenüber stehst? Wenn das eben nicht so ist, dass man etwas von großer Komplexität in drei Zeilen ausreichend und allgemeinverbindlich erklären kann?
Scripts können so etwas, wie die autoxec.bat früher, aber sie können noch sehr viel mehr.
Hier kommt nun eine Platzverschwendung, nämlich das script zu dem Befehl pkg_libchk aus sysutils/bsdadminscripts:
Code:
#!/bin/sh -f
#
# Copyright (c) 2007-2009
# Dominic Fandrey <kamikaze@bsdforen.de>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
readonly name=pkg_libchk
readonly version=1.6.1
readonly osname=`uname -s`
readonly pkgng=`make -f /usr/share/mk/bsd.port.mk -V WITH_PKGNG`
# Use a line break as delimiter.
IFS='
'
# Filename prefix for shared data
sharedprefix="/tmp/$$"
shared="locks"
#
# This function remembers a lock to allow later deletion with the
# lockUnregisterAll() function.
#
# @param $1
# The name of the lock.
lockRegister() {
local lock
lock="$sharedprefix-$shared"
lockf -k "$lock" sh -c "
if ! grep -qE '^$1\$' '$lock'; then
echo '$1' >> '$lock'
fi
"
}
#
# Unregisters all locks.
#
lockUnregisterAll() {
wait
for register in $(cat "$sharedprefix-$shared"); {
lockf "$sharedprefix-$register" wait
}
lockf "$sharedprefix-$shared" wait
}
#
# This function creates a semaphore.
#
# @param $1
# The name of the semaphore.
# @param $2
# The size of the semaphore.
#
semaphoreCreate() {
local lock
lockRegister "semaphore-$1"
lock="$sharedprefix-semaphore-$1"
lockf -k "$lock" echo "$2" > "$lock"
eval "semaphore_$1_size=$2"
}
#
# This function waits until the semaphore is free und registers its use.
# Everything that uses this also has to call the semaphoreFree() function.
#
# @param $1
# The name of the semaphore.
#
semaphoreUse() {
local lock semaphores
lock="$sharedprefix-semaphore-$1"
while ! lockf -k "$lock" sh -c "
state=\$(cat '$lock')
if [ \"\$state\" -gt 0 ]; then
echo \"\$((\$state - 1))\" > '$lock'
exit 0
fi
exit 1
"; do
sleep 0.1
done
}
#
# This function frees a semaphore.
#
# @param $1
# The name of the semaphore.
#
semaphoreFree() {
local lock
lock="$sharedprefix-semaphore-$1"
lockf -k "$lock" sh -c "
state=\"\$((\"\$(cat '$lock')\" + 1))\"
echo \"\$state\" > '$lock'
"
}
#
# This function sets a new status and prints it.
#
# @param $1
# The status message.
# @param $clean
# If set status handling is disabled.
#
statusSet() {
# In clean mode status handling is disabled.
test -z "$clean" || return 0
local lock
lock="$sharedprefix-status"
lockf -k "$lock" sh -c "
status=\"\$(cat '$lock')\"
echo '$1' > '$lock'
printf \"\\r%-\${#status}s\\r\" '$1' > /dev/tty
"
}
#
# This function prints a message and the current status behind it.
#
# @param $1
# The message to print.
# @param $clean
# If set the status will not be printed.
#
statusPrint() {
if [ -z "$clean" ]; then
local lock
lock="$sharedprefix-status"
lockf -k "$lock" sh -c "
status=\"\$(cat '$lock')\"
printf \"%-\${#status}s\\r\" '' > /dev/tty
echo '$1'
printf '%s\\r' \"\$status\" > /dev/tty
"
else
echo "$1"
fi
}
#
# Waits for a semaphore to be completely free and counts down the remaining
# number of locks.
#
# @param $1
# The semaphore to watch.
# @param $2
# The status message to print, insert %d in the place where the number
# of remaining locks belong.
#
semaphoreCountDown() {
local free size
while read -t1 free < "$sharedprefix-semaphore-$1"; do
size=$(eval "echo \$semaphore_$1_size")
statusSet "$(printf "$2" $(( $size - $free )))"
test "$free" -eq "$size" && break
sleep 0.1
done
wait
}
# Clean up upon exit.
trap '
semaphoreCountDown jobs "Terminated by signal, waiting for %d jobs to die."
echo > /dev/tty
lockUnregisterAll
exit 255
' int term
#
# This function checks whether a given binary or library directly depends
# on a missing library.
# It goes a long way to prevent all kinds of false positives.
# It always returns 2 (false) for Linux and other non-native libraries
# and binaries.
# It also checks whether the missing dependency is really a direct dependency
# (indirect dependencies have to be fixed somewhere else).
#
# @param $1
# The library or binary to check.
# @return
# Returns 0 (true) if a library is missing.
# Returns 1 if everything is all right.
# Returns 2 if the check cannot be performed (not a native library).
#
dependencyMissing() {
local missing file direct libfound
# We cannot handle non-native binaries,
# so assume everything is in order.
if ! readelf -e "$1" 2>&1 | \
grep -E "^[[:space:]]*OS/ABI:[[:space:]]*UNIX - $osname\$" \
> /dev/null
then
return 2
# Nothing is missing.
elif ! missing="$(ldd "$1" 2>&1 | grep -E "$match_expr")"; then
return 1
fi
# The return status. The value 1 assumes that this is a false positive.
status=1
# Only report misses for direct dependencies.
direct="$(
readelf -d "$1" 2> /dev/null | \
grep 'Shared library:' | \
sed -E -e 's|^[^[]*\[||1' -e 's|\]$||1'
)"
# Compare every missing depency with the list of direct dependencies
# and report that the dependency is missing if the missing file is
# a direct dependency.
for file in $missing; {
# Strip the missing file of additional information.
file="$(echo "$file" | sed -E \
-e 's| => .*$||1' \
-e 's|^[[:space:]]*||1' \
-e 's|^.*dependency ||1' \
-e 's| not found$||1'
)"
# If in mean mode we do not check for false positives.
if [ -n "$mean" ]; then
test -n "$raw" && return 0
statusPrint "$package_name: $1 misses $file"
continue
fi
# Handle the case where a library is not found, but exists
# somewhere in the package. This is for packages that do not
# rely on the OS to find libraries.
libfound=
for library in $(echo "$libraries" | grep -E "/$file\$"); {
# The library exists after all.
test -e "$library" && libfound=1 && break
}
if test "$libfound"; then
test -n "$verbose" && statusPrint "$package_name: \
located: $1 misses $file found at $library."
continue
fi
# Compare the file with the list of direct dependencies.
# If it's not in than it's only an indirect dependency and
# cannot be fixed by rebuilding this port.
if echo "$direct" | grep -E "^$file\$" > /dev/null; then
test -n "$raw" && return 0
statusPrint "$package_name: $1 misses $file"
status=0
elif [ -n "$verbose" ]; then
statusPrint "$package_name: inderect: $1 \
misses $file is an inderect dependency."
fi
}
return $status
}
#
# Checks the parameters for options.
#
# @param $packages
# The parameters to pkg_info -E that will result in the
# names of the packages to work on.
# @param $recursive
# Contains the appropriate parameter to get the
# dependencies of the given packages from pkg_info.
# @param $Recursive
# Contains the appropriate parameter to get the
# packages depending on the given packages from pkg_info.
# @param $raw
# Is set to trigger raw printing.
# @param $clean
# Is set to trigger printing without status messages.
# @param $verbose
# Is set to be verbose about false positives.
# @param $mean
# Is set to switch into mean mode. That means no
# checking of false positives.
# @param $compat
# Delete to avoid detecting compat libraries as misses.
# @param $origin
# Is set to turn the print origin mode on.
# @semaphore jobs
# Is set to limit the amount of parallel jobs.
#
readParams() {
local option
for option {
case "$option" in
"-a" | "--all")
packages="-a"
;;
"-c" | "--clean")
clean=1
;;
"-h" | "--help")
printHelp
;;
-j* | --jobs*)
local jobs
jobs="${option#-j}"
jobs="${jobs#--jobs}"
if [ "$jobs" -ne "$jobs" ] 2> /dev/null; then
echo "The -j option must be followed" \
"by a number."
exit 3
elif [ "$jobs" -lt 1 ]; then
echo "The -j option must specify at" \
"least 1 job."
exit 3
else
semaphoreCreate jobs "$jobs"
fi
;;
"-m" | "--mean")
mean=1
;;
"-n" | "--no-compat")
compat=
;;
"-o" | "--origin")
origin=1
;;
"-q" | "--raw")
raw=1
if [ -n "$verbose" ]; then
echo "The parameters -v and -q may" \
"not be used at the same time."
exit 2
fi
;;
"-r" | "--recursive")
recursive="-r"
;;
"-R" | "--upward-recursive")
Recursive="-R"
;;
"-v" | "--verbose")
verbose=1
if [ -n "$raw" ]; then
echo "The parameters -q and -v may" \
"not be used at the same time."
exit 2
fi
;;
-? | --*)
echo "Unknown parameter \"$option\"."
exit 1
;;
-*)
readParams "${option%${option#-?}}"
readParams "-${option#-?}"
;;
*)
packages="$packages${packages:+$IFS}$option"
;;
esac
}
}
#
# Display a short help message.
#
printHelp() {
echo "$name v$version
usage: $name [-a] [-c] [-h] [-jN] [-m] [-n] [-o] [-q] [-r] [-R] [-v] [packages]"
exit 0
}
# Create the expression to match to find files linking against compat libraries.
# This can be emptied by readParams to deactivate that feature.
prefix="$(make -f /usr/share/mk/bsd.port.mk -VPREFIX 2> /dev/null || \
echo '/usr/local')"
compat="=> $prefix/lib/compat|"
# Create the semaphore with CPU cores * 2 jobs.
semaphoreCreate jobs "$(($(sysctl -n hw.ncpu 2> /dev/null || echo 1) * 2))"
# Register the status lock.
lockRegister status
# Read the parameters.
readParams "$@"
statusSet 'Preparing ...'
# Get the packages to work on.
test -z "$packages" && packages="-a"
if [ -n "$pkgng" ]; then
packages="$(pkg info -q $packages)"
test -z "$recursive" -a -z "$Recursive" || packages="$packages
$(pkg info -q $recursive $Recursive "$packages" 2> /dev/null | \
sed -E 's|^@pkgdep[[:space:]]*||1')"
else
packages="$(pkg_info -E $packages)"
test -z "$recursive" -a -z "$Recursive" || packages="$packages
$(pkg_info -q $recursive $Recursive "$packages" 2> /dev/null | \
sed -E 's|^@pkgdep[[:space:]]*||1')"
fi
# Create the regexp to match ldd output
match_expr="$compat=> not found|dependency .+ not found"
# The packages to check.
package_amount="$(echo "$packages" | wc -l | sed 's|[[:space:]]||g')"
package_num=0
# Check each selected package.
for package in $packages; {
package_num="$(($package_num + 1))"
if [ -n "$pkgng" ]; then
test $origin \
&& package_name="$(pkg info -qo "$package")" \
|| package_name="$package"
else
test $origin \
&& package_name="$(pkg_info -qo "$package")" \
|| package_name="$package"
fi
# Print what we're doing.
statusSet "Starting job $package_num of $package_amount: $package_name"
semaphoreUse jobs
(
# Remember freeing the semaphore.
trap 'semaphoreFree jobs' EXIT
files=""
if [ -n "$pkgng" ]; then
files="$(pkg info -lq "$package")"
else
files="$(pkg_info -qL "$package")"
fi
# Get the programs libraries in case it doesn't use the
# operating system to find its libraries.
libraries="$(echo "$files" | grep -E '\.so[\.0-9]*$')"
outdated=0
broken=
# Check each file of each package.
for file in $files; {
if [ ! -L "$file" -a \( \
-x "$file" -o \
-n "$(echo "$file" | grep -E '\.so[\.0-9]*$')" \
\) ]; then
if dependencyMissing "$file"; then
if [ -n "$raw" ]; then
statusPrint "$package_name"
break 1
fi
fi
fi
}
) &
}
semaphoreCountDown jobs "Waiting for %d remaining jobs to finish."
statusSet
lockUnregisterAll
exit 0
Ich erlaube mir das hierher zu stellen, weil die Codeblöcke sich ja selbst einschrumpfen. Es soll nur ein Beispiel sein. Das kannst du lesen und daraus lernen und mit weiteren Scripten geht das ebenso. Ein Script muss nicht die Endung .sh haben, aber manche Editoren erkennen sie daran und färben dann bestimmte Teile so ein, dass sie einfacher zu erkennen sind oder erlauben sogar Testläufe. Grundsätzlich werden scripte über sh(1) aufgerufen und wie fast immer erklärt einem dazu die man-page einiges. Scripte können aber auch durch bestimmte Automatismen aufgerufen werden (zB durch andere Scripte) und müssen dafür dann oft an einem bestimmten Ort gefunden werden und ausführbar sein.
Auch Kommandos wie ls(1) lassen sich in scripten verwenden, aber natürlich sieht ein Script nicht mit Menschen-Augen die Ausgabe des Kommandos. Deshalb sind bunte Ausgaben auch nicht sinnvoll und wenn du wissen möchtest, wieso die Option -G etwas einfärbt, dann müsstest du den Programmierer dieses Tools fragen, wenn du aber wissen möchtest, wie man darauf kommt, solche Optionen zu nutzen, dann ist wieder die Lektüre der man-page hilfreich. Und wenn du nicht weißt, wie "man" geht, hilft auch wieder die man-page, einfach mit "man man" zu erreichen.
man und info -Seiten sind eine großartige Hilfe und ich nutze die dauernd, weil ich mir befehle kaum merken kann. Aber, sich die Funktion eines Betriebssystems oder auch nur die Möglichkeiten von Scripten darüber zu erschließen, hatte mich sehr schnell überfordert. Gute Bücher sind da sicher eher zu empfehlen. Eines, meiner ersten, das nicht mal gut ist, war Linux für Dummies. Das ist immerhin recht dünn und überschaubar. Ansonsten hatte ich damals mit SuSE-Linux angefangen und die lieferten sehr gute Dokumentationen mit. Mehr gelernt habe ich dann aber durch Lektüren im Internet, wobei sich auch immer mehr unbrauchbarer Ballast ansammelt.
http://www.selflinux.org/selflinux/ war damals eine Anlaufstelle für Grundverständnis und ich möchte neben unserem eigenen Wiki auch das
https://wiki.ubuntuusers.de nennen, wo viele Dinge sehr gut für Erstanwender beschrieben sind.
Die beste Hilfe ist schließlich: versuch es selbst und erkenne deine Irrtümer.