How to delete '$'\n' characters appended to ldd list - bash

I am trying to copy binary dependencies to other folder, so I use ldd to see what should be copied.
However the script fails when copying. It "appears" '$'\n' characters when binary dependencies are copied.
Something is wrong, but I dont know what. Tried running command per command and cant see the fault.
What is the trouble here ?
Thanks
Script code
#!/usr/bin/env bash
set -e
chr=/home/myjail
cmds=( bash echo ls rm )
mkdir -p "$chr"/{bin,lib,lib64}
# copy commands
for app in "${cmds[#]}"; do
echo 'Added command:'"$app"
cp -v /bin/"$app" "$chr/bin"
done
# copy deps
for app in "${cmds[#]}";do
echo 'deps for:'"$app"
deps="$(ldd /bin/"$app" | egrep -o '/lib.*\.[0-9]')"
for curdep in "${deps[#]}";do
echo "$curdep"
cp -v --parents "$curdep" "$chr"
done
done
Script output
furby#debian-haptic20:~# ./depcopy.sh
Added command:bash
'/bin/bash' -> '/var/lib/haproxy/bin/bash'
Added command:echo
'/bin/echo' -> '/var/lib/haproxy/bin/echo'
Added command:ls
'/bin/ls' -> '/var/lib/haproxy/bin/ls'
Added command:mysql
'/bin/mysql' -> '/var/lib/haproxy/bin/mysql'
deps for:bash
/lib/x86_64-linux-gnu/libtinfo.so.6
/lib/x86_64-linux-gnu/libdl.so.2
/lib/x86_64-linux-gnu/libc.so.6
/lib64/ld-linux-x86-64.so.2
cp: failed to get attributes of '/lib/x86_64-linux-gnu/libtinfo.so.6'$'\n': No such file or directory

I'm using this script for this purpose:
copydep.sh
#!/bin/bash
if [ ${#} != 2 ]
then
echo "usage $0 PATH_TO_BINARY target_folder"
exit 1
fi
path_to_binary="$1"
target_folder="$2"
# if we cannot find the the binary we have to abort
if [ ! -f "${path_to_binary}" ]
then
echo "The file '${path_to_binary}' was not found. Aborting!"
exit 1
fi
# copy the binary itself
echo "---> copy binary itself"
cp --parents -v "${path_to_binary}" "${target_folder}"
# copy the library dependencies
echo "---> copy libraries"
ldd "${path_to_binary}" | awk -F'[> ]' '{print $(NF-1)}' | while read -r lib
do
[ -f "$lib" ] && cp -v --parents "$lib" "${target_folder}"
done
Run it like this:
$ mkdir /tmp/test
$ bash copydep.sh /bin/ls /tmp/test
---> copy binary itself
/bin -> /tmp/test/bin
'/bin/ls' -> '/tmp/test/bin/ls'
---> copy libraries
/lib -> /tmp/test/lib
/lib/x86_64-linux-gnu -> /tmp/test/lib/x86_64-linux-gnu
'/lib/x86_64-linux-gnu/libselinux.so.1' -> '/tmp/test/lib/x86_64-linux-gnu/libselinux.so.1'
'/lib/x86_64-linux-gnu/libc.so.6' -> '/tmp/test/lib/x86_64-linux-gnu/libc.so.6'
'/lib/x86_64-linux-gnu/libpcre.so.3' -> '/tmp/test/lib/x86_64-linux-gnu/libpcre.so.3'
'/lib/x86_64-linux-gnu/libdl.so.2' -> '/tmp/test/lib/x86_64-linux-gnu/libdl.so.2'
/lib64 -> /tmp/test/lib64
'/lib64/ld-linux-x86-64.so.2' -> '/tmp/test/lib64/ld-linux-x86-64.so.2'
'/lib/x86_64-linux-gnu/libpthread.so.0' -> '/tmp/test/lib/x86_64-linux-gnu/libpthread.so.0'
# Result:
$ tree /tmp/test/
/tmp/test/
├── bin
│   └── ls
├── lib
│   └── x86_64-linux-gnu
│   ├── libc.so.6
│   ├── libdl.so.2
│   ├── libpcre.so.3
│   ├── libpthread.so.0
│   └── libselinux.so.1
└── lib64
└── ld-linux-x86-64.so.2
4 directories, 7 files

Your deps variable should be an array, created with mapfile and some redirection of process substitution:
mapfile -t deps < <(ldd /bin/"$app" | grep -o '/lib.*\.[0-9]')
As you have it, it's treated as a single string, which as you've seen, doesn't work.

Related

tree negative pattern not working with watch

I want to watch the tree structure of a directory.
If I call tree -L 2 -I '*vfp*' all is well and I see no directories
.
0 directories, 0 files
...but if I try and watch tree -L 2 -I '*vfp*' I see everything without the effect of -I
Every 2,0s: tree -L 2 -I *vfp*
vfp-directory
├── ckpts
├── data
│ ├── 100.wav
│ ├── 101.wav
│ ├── 102.wav
...
What am I missing here? How can I watch the directory and see the same as what I see with a bare call to tree?
When you do :
watch tree -L 2 -I '*vfp*'
What watch sees is :
tree -L 2 -I *vfp*
So you need to do
watch tree -L 2 -I "'*vfp*'"
The reason why watch sees differently has to do with how bash parses command line.
When bash parses this line :
watch tree -L 2 -I '*vfp*'
it removes quotes around the arguments, so it runs watch command with 5 arguments : [tree], [-L], [2], [-I], [*vfp*].
I believe you have to escape your single quotes:
watch tree -L 2 -I \'*vfp*\'

rpm build error : cannot create regular file | no such file or directory [duplicate]

This question already has answers here:
Are shell scripts sensitive to encoding and line endings?
(14 answers)
Closed 8 months ago.
Linux Distribution: Ubuntu 20
(So using the rpm package not rpmdevtools-package to build the rpm)
Folder structure of rpmbuild:
rpmbuild
├── BUILD
│   └── alascript-1
│   ├── config.cfg
│   ├── logfile.txt
│   └── script.sh
├── BUILDROOT
│   └── alascript-1-0.x86_64
│   └── etc
│   └── alascript\015
├── RPMS
├── SOURCES
│   ├── alascript-1
│   │   ├── config.txt
│   │   ├── logfile.txt
│   │   └── script.sh
│   └── alascript-1.0.tar.gz
├── SPECS
│   └── alascript.spec
└── SRPMS
The alascript-1.0.tar.gz is the tar file of the above folder i.e alascript-1.
Here's my spec file:
Name: alascript
Version: 1
Release: 0
Summary: A Bash Script for secure copying from eNodeB to server.
Group: theogs
BuildArch: noarch
License: GPL
URL: https://github.com/
Source0: alascript-1.0.tar.gz
%description
The bash script will basically secure copy files
from the eNodeB to server and then those files will be
processed using ML Ananlyser.
%prep
%setup -q
%build
%install
install -m 0755 -d $RPM_BUILD_ROOT/etc/alascript
install -m 0600 config.cfg $RPM_BUILD_ROOT/etc/alascript/config.cfg
install -m 0644 logfile.txt $RPM_BUILD_ROOT/etc/alascript/logfile.txt
install -m 0755 script.sh $RPM_BUILD_ROOT/etc/alascript/script.sh
%files
/etc/alascript
/etc/alascript/config.cfg
/etc/alascript/script.sh
/etc/alascript/logfile.txt
%changelog
* Mon Jun 20 2022 theogs 1.0.0
- Initial rpm release
Now when I try to run the command : rpmbuild -ba SPECS/alascript.spec
I get the following output:
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.wSNbxX
+ umask 022
+ cd /home/test/rpmbuild/BUILD
+ cd /home/test/rpmbuild/BUILD
+ rm -rf alascript-1
+ /bin/gzip -dc /home/test/rpmbuild/SOURCES/alascript-1.0.tar.gz
+ /bin/tar -xof -
+ STATUS=0
+ [ 0 -ne 0 ]
+ cd alascript-1
+ /bin/chmod -Rf a+rX,u+w,g-w,o-w .
+ exit 0
Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.CCUFwV
+ umask 022
+ cd /home/test/rpmbuild/BUILD
+ cd alascript-1
+ exit 0
Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.BT4UXX
+ umask 022
+ cd /home/test/rpmbuild/BUILD
+ cd alascript-1
+ install -m 0755 -d /home/test/rpmbuild/BUILDROOT/alascript-1-0.x86_64/etc/alascript
+ install -m 0600 config.cfg /home/test/rpmbuild/BUILDROOT/alascript-1-0.x86_64/etc/alascript/config.cfg
install: cannot create regular file '/home/test/rpmbuild/BUILDROOT/alascript-1-0.x86_64/etc/alascript/config.cfg'$'\r': No such file or directory
error: Bad exit status from /var/tmp/rpm-tmp.BT4UXX (%install)
I am fairly new to bash and shell scripting and have never made a rpm package.
I can't figure out what's the issue.
Also the reference blog I am following: How to Create a RPM Pakcage
You look to have some special characters within the SPEC File
Visible when you have shown the directory tree
└── alascript\015
015 (Octal) is CR (Carriage return)
Did you copy and paste a part of the code from somewhere?
Easiest fix is to run the spec file through a formatting tool like dos2unix

gccgo build can not find custom pakage

when use the gccgo build one single go file is ok, but whn I build a large multi custom pacage go mod project, the project have some sub package(such as app/ app/core/server etc) not build success.
how to fix this? anyhelp? I build with -x and see some debug info.
go build -x -gccgoflags -Wl,-R,/opt/gccgo/lib64/ -compiler gccgo -o bin/app main.go
the error is:
WORK=/tmp/go-build1609005358
mkdir -p $WORK/b001/
cd $WORK
/opt/gccgo/bin/gccgo -fgo-importcfg=/dev/null -c -x c - -o /dev/null || true
mkdir -p $WORK/b001/_importcfgroot_/github.com/gin-gonic
ln -s /home/liangqi1/.cache/go-build/8a/8ae3d6bb3097698b7be6547599d7a61c9c5c54cca0be55c007ca1c8386d1188c-d $WORK/b001/_importcfgroot_/github.com/gin-gonic/libgin.a
mkdir -p $WORK/b001/_importcfgroot_/github.com/logrusorgru
ln -s /home/liangqi1/.cache/go-build/6f/6fb602f3c990310188a3e921909d152810f07d50f1ab4c621ab71b87afd4942d-d $WORK/b001/_importcfgroot_/github.com/logrusorgru/libaurora.a
mkdir -p $WORK/b001/_importcfgroot_/go.uber.org
ln -s /home/liangqi1/.cache/go-build/c0/c0ac9f2f0ebb74e0997bfa1d72d21a79ce906ed736197f83402365203094c3a9-d $WORK/b001/_importcfgroot_/go.uber.org/libautomaxprocs.a
/opt/gccgo/bin/gccgo -ffile-prefix-map=a=b -c -x c - -o /dev/null || true
cd /home/liangqi1/gccgo_demo
/opt/gccgo/bin/gccgo -c -g -m64 -fdebug-prefix-map=$WORK=/tmp/go-build -gno-record-gcc-switches -fgo-relative-import-path=_/home/liangqi1/gccgo_demo -o $WORK/b001/_go_.o -I $WORK/b001/_importcfgroot_ -Wl,-R,/opt/gccgo/lib64/ ./main.go
# command-line-arguments
./main.go:7:23: 错误:import file ‘gccgo_demo/app’ not found
7 | "gccgo_demo/app"
| ^
./main.go:8:35: 错误:import file ‘gccgo_demo/app/core/server’ not found
8 | "gccgo_demo/app/core/server"
| ^
./main.go:24:19: 错误:reference to undefined name ‘app’
24 | if err := app.Init(prjHome); err != nil {
| ^
./main.go:29:12: 错误:reference to undefined name ‘app’
29 | if app.IsProd() {
| ^
./main.go:35:9: 错误:reference to undefined name ‘server’
35 | server.Run()
| ^
the gccgo just clone from gcc git:
gccgo (GCC) 12.0.1 20220217
go version is 1.16.4
my project struct like flow:
gccgo_demo
├── app
│   ├── app.go
│   ...
├── go.mod
├── go.sum
├── main.go
... other code
the go mod name is gccgo_demo so , the app/app.go has some import like gccgo_demo/app path.
I don't see your code but I guess the problem that you do not pass the include path.
The cgo tool will always invoke the C compiler with the source file's directory in the include path; i.e. -I${SRCDIR} is always implied. This means that if a header file foo/bar.h exists both in the source directory and also in the system include directory (or some other place specified by a -I flag), then "#include <foo/bar.h>" will always find the local version in preference to any other version.
So just do smth like
go build -x -gccgoflags -I/path/to/your/file -Wl,-R,/opt/gccgo/lib64/ -compiler gccgo -o bin/app main.go
More details https://pkg.go.dev/cmd/cgo

create tar and save it to stdout

I am trying to create tar from a file, which contains list of other files and saving it to stdout.
let suppose there is a file called "files-to-create" which has path of other files like /home/abc.txt /home/def.txt and I want to create tar of abc.txt,def.txt.
my script contains:
exec 100>&1
tar cf - -T files-to-sync >&100
and I am calling the script and saving it to some other file like:
/script.sh > final_tar.tar
But while creating the tar I am getting error, can somebody help me out?
You can use the following script to reach your goal, let me know if something is unclear:
Prototype 1:
$ cat scriptTar.sh
#!/bin/bash
readonly HELP="$(basename "$0") <list_of_files> <output_tar>
this script will generate a tar file composed of all files present in <list_of_files> input file
the output tar file will be saved as <output_tar>
to run the script provide the input and output filenames"
readonly INPUT_LIST_FILE=$1
readonly OUTPUT_TAR_FILE=$2
if [ -z "$INPUT_LIST_FILE" -o -z "$OUTPUT_TAR_FILE" ]
then
echo $HELP;
exit 1;
fi
tar cf - -T $INPUT_LIST_FILE > $OUTPUT_TAR_FILE
exit $?
Folder content:
$ tree .
.
├── a
│   └── abc.txt
├── b
│   └── def.txt
├── c
│   └── ghj.txt
├── files-to-sync.in
└── scriptTar.sh
3 directories, 5 files
List file content:
$ cat files-to-sync.in
./a/abc.txt
./b/def.txt
./c/ghj.txt
Execution:
$ ./scriptTar.sh files-to-sync.in output.tar
tar file content:
$ tar -tvf output.tar
-rw-rw-r-- arobert/arobert 4 2018-02-22 16:50 ./a/abc.txt
-rw-rw-r-- arobert/arobert 4 2018-02-22 16:50 ./b/def.txt
-rw-rw-r-- arobert/arobert 4 2018-02-22 16:50 ./c/ghj.txt
Or use the following script if you really want to display it on stdout:
Prototype 2 via ssh:
#!/bin/bash
readonly HELP="ERROR: $(basename "$0") <list_of_files>
this script will generate to stdout a tar file composed of all files present in <list_of_files> input file
to run the script provide the input file and redirect the output to a file"
readonly INPUT_LIST_FILE=$1
if [ -z "$INPUT_LIST_FILE" ]
then
echo $HELP;
exit 1;
fi
tar cf - -T $INPUT_LIST_FILE
Execution via ssh:
$ ssh user#localhost "cd /home/user/test_tar/; ./scriptTar.sh files-to-sync.in" > output.tar
user#localhost's password:
Content of the tar generated:
tar -tf output.tar
./a/abc.txt
./b/def.txt
./c/ghj.txt
extracting the content:
tar xvf output.tar
./a/abc.txt
./b/def.txt
./c/ghj.txt
checking the files:
more ?/*.txt
::::::::::::::
a/abc.txt
::::::::::::::
abc
::::::::::::::
b/def.txt
::::::::::::::
abc
::::::::::::::
c/ghj.txt
::::::
However if I were you, I would not only generate a tar file but add some compression (tar.gz) and transfer the file with rsync to be able to restart the download from the point where it stopped in case of transfer error.
So the proper solution is
Case1: If you are passing the list of file as an argument
you can use this:
files-to-sync=$1
tar cf - -T files-to-sync
Case2: If you want to use absolute path for the list of file
you can use this:
tar cfP - -T /path/to/the/file
use -P in case of absolute path.

How to extract nested tar.gz files easily?

I need to extract tar.gz a file. It's about 950mb. It has another 23 tar.gz files in it. Each of those 23 tar.gz files has one tar file in them. My questions is how I can easily extract all of them? Is there a commandline tool that I can use?
The structure is like the following:
foo.tar.gz
├───bar1.tar.gz
│ ├───foobar1.tar
├───bar2.tar.gz
│ ├───foobar2.tar
├───bar3.tar.gz
│ ├───foobar3.tar
├───bar4.tar.gz
│ ├───foobar4.tar
├───bar5.tar.gz
│ ├───foobar5.tar
├───bar6.tar.gz
│ ├───foobar6.tar
| ..........
| ..........
| ..........
| 23 of them
Thanks in advance.
You can use the --to-command argument to pass each extracted file to another program (on stdin). In this case, you pass it to another tar instance reading data from stdin.
tar --to-command='tar -xzvf -' -xzvf foo.tar.gz
I ended up manually extracted foo.tar.gz and using the following shell script to extract those bar*.tar.gz files.
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
for next in *.tar.gz
do
echo "Untaring - $next"
tar -xzf $next -C ~/foo
done
exit 0
hope this will help someone.
Yup.
tar -xzOf foo.tar.gz bar1.tar.gz | tar -xO foobar1.tar
Should do the trick.

Resources