Using shebang in a spec file without it being a comment - rpmbuild

I need to make a small wrapper script around the binary I'm packing in an RPM. That wrapper script needs to say "#!/bin/sh" at the top. But when I do that, the "#..." is treated like a comment. No, don't comment that.
Is there any way to use a predefined variable or escape sequence to make a shebang (on the first line)?
Here's my little code in the .spec file:
%build
echo #!/bin/bash > foobar
echo export LD_LIBRARY_PATH=/opt/foobar/foobar/lib >> foobar
echo /opt/foobar/lib/foobar >> foobar
echo exit $? >> foobar
... where the result of the 1st line in the %build cycle is simply "+ echo."
Must I take a different approach? If so, what approach?

Just coming back to my question.
Quote the hash-bang. 'nuff said.Thanks.

Related

trying to display file with echo command (with or without quotes)

So when I try to do
echo cat file1.txt
The output is cat file.txt
However, when I do:
echo 'cat file1.txt'
The output is the actual contents of the file1.txt
Although I recognize the echo command is not required at all to achieve the goal of displaying the file contents, I was curious as to why the outputs differed in these given situations
As you are confused about behaviour
Every unix statment inside `` is considered as a saparate command
you can directly use `` on command to assign the output of command into that variable
see below:
[cloudera#quickstart sub1]$ a=`echo "Hello"`
[cloudera#quickstart sub1]$ echo $a
Hello
[cloudera#quickstart sub1]$
in above example you can see i am assigning the output of echo "Hello" to a variable named a
Are you sure you typed
echo 'cat file.txt'
and not
echo `cat file.txt`
?
In the first case, I have no clue what’s going on. In the second, however, there is no mystery. In most shells, typing
foo `bar`
means, somewhat (over)simplified, "run bar, and use its output as the command parameters for running foo".
If you are running Bash, this is described in the section on command substitution in the manual.

Make zsh complete arguments from a file

zsh is great but its completion system is very diverse. And the documentation lacks good examples. Is there a template for completing for a specific application. The completion would get its match data from a file, separated by newlines?
I tried modifying an older example of mine that takes match data "live":
~ % cat .zsh/completers/_jazzup
#compdef jazz_up
_arguments "2: :(`mpc lsplaylists|sed -e 's# #\\\\ #g'`)"
I could supply cat my_file there instead of mpc invocation and so on but would there be a more elegant way to do this simple task? And that completion there is placement-specific: can you provide an example where zsh would attempt to complete at any point after the program name is recognized?
The match data will have whitespaces and so on, the completion should escape the WS. Example of that:
Foo bar
Barbaric
Get it (42)
Now if that completion would be configured for a command Say, we should get this kind of behaviour out of zsh:
$ Say Fo<TAB>
$ Say Foo\ bar
$ Say Ge<TAB>
$ Say Get\ it\ \(42\)
Simple completion needs are better addressed with _describe, it pairs an array holding completion options and a description for them (you can use multiple array/description pairs, check the manual).
(_arguments is great but too complex.)
[...]
First create a file
echo "foo\nbar\nbaz\nwith spac e s\noh:noes\noh\:yes" >! ~/simple-complete
Then create a file _simple somewhere in your $fpath:
#compdef simple
# you may wish to modify the expansion options here
# PS: 'f' is the flag making one entry per line
cmds=( ${(uf)"$(< ~/simple-complete)"} )
# main advantage here is that it is easy to understand, see alternative below
_describe 'a description of the completion options' cmds
# this is the equivalent _arguments command... too complex for what it does
## _arguments '*:foo:(${cmds})'
then
function simple() { echo $* }
autoload _simple # do not forget BEFORE the next cmd!
compdef _simple simple # binds the completion function to a command
simple [TAB]
it works. Just make sure the completion file _simple is placed somewhere in your fpath.
Notice that : in the option list is supposed to be used for separating an option from their (individual) description (oh:noes). So that won't work with _describe unless you quote it (oh\:yes). The commented out _arguments example will not use the : as a separator.
Without changing anything further in .zshrc (I already have autoload -Uz compinit
compinit) I added the following as /usr/local/share/zsh/site-functions/_drush
#compdef drush
_arguments "1: :($(/usr/local/bin/aliases-drush.php))"
Where /usr/local/bin/aliases-drush.php just prints a list of strings, each string being a potential first argument for the command drush. You could use ($(< filename)) to complete from filename.
I based this on https://unix.stackexchange.com/a/458850/9452 -- it's surprising how simple this is at the end of the day.

How to read 1 symbol in zsh?

I need to get exactly one character from console and not print it.
I've tried to use read -en 1 as I did using bash. But this doesn't work at all.
And vared doesn't seem to have such option.
How to read 1 symbol in zsh? (I'm using zsh v.4.3.11 and v.5.0.2)
read -sk
From the documentation:
-s
Don’t echo back characters if reading from the terminal. Currently does not work with the -q option.
-k [ num ]
Read only one (or num) characters. All are assigned to the first name, without word splitting. This flag is ignored when -q is present. Input is read from the terminal unless one of -u or -p is present. This option may also be used within zle widgets.
Note that despite the mnemonic ‘key’ this option does read full characters, which may consist of multiple bytes if the option MULTIBYTE is set.
If you want your script to be a bit more portable you can do something like this:
y=$(bash -c "read -n 1 c; echo \$c")
read reads from the terminal by default:
% date | read -sk1 "?Enter one char: "; echo $REPLY
Enter one char: X
Note above:
The output of date is discarded
The X is printed by the echo, not when the user enters it.
To read from a pipeline, use file descriptor 0:
% echo foobar | read -rk1 -u0; echo $REPLY
f
% echo $ZSH_VERSION
5.5.1
Try something like
read line
c=`echo $line | cut -c1`
echo $c

Unix: prepending a file without a dummy-file?

I do not want:
$ cat file > dummy; $ cat header dummy > file
I want similar to the command below but to the beginning, not to the end:
$ cat header >> file
You can't append to the beginning of a file without rewriting the file. The first way you gave is the correct way to do this.
This is easy to do in sed if you can embed the header string directly in the command:
$ sed -i "1iheader1,header2,header3"
Or if you really want to read it from a file, you can do so with bash's help:
$ sed -i "1i$(<header)" file
BEWARE that "-i" overwrites the input file with the results. If you want sed to make a backup, change it to "-i.bak" or similar, and of course always test first with sample data in a temp directory to be sure you understand what's going to happen before you apply to your real data.
The whole dummy file thing is pretty annoying. Here's a 1-liner solution that I just tried out which seems to work.
echo "`cat header file`" > file
The ticks make the part inside quotes execute first so that it doesn't complain about the output file being an input file. It seems related to hhh's solution but a bit shorter. I suppose if the files are really large this might cause problems though because it seems like I've seen the shell complain about the ticks making commands too long before. Somewhere the part that is executed first must be stored in a buffer so that the original can be overwritten, but I'm not enough of an expert to know what/where that buffer would be or how large it could be.
You can't prepend to a file without reading all the contents of the file and writing a new file with your prepended text + contents of the file. Think of a file in Unix as a stream of bytes - it's easy to append to an end of a stream, but there is no easy operation to "rewind" the stream and write to it. Even a seek operation to the beginning of the file will overwrite the beginning of with any data you write.
One possibility is to use a here-document:
cat > "prependedfile" << ENDENDEND
prepended line(s)
`cat "file"`
ENDENDEND
There may be a memory limitation to this trick.
Thanks to right searchterm!
echo "include .headers.java\n$(cat fileObject.java )" > fileObject.java
Then with a file:
echo "$(cat .headers.java)\n\n$(cat fileObject.java )" > fileObject.java
if you want to pre-pend "header" to "file" why not append "file" to "Header"
cat file >> header
Below is a simple c-shell attempt to solve this problem. This "prepend.sh" script takes two parameters:
$1 - The file containing the pre-appending wording.
$2 - The original/target file to be modified.
#!/bin/csh
if (if ./tmp.txt) then
rm ./tmp.txt
endif
cat $1 > ./tmp.txt
cat $2 >> ./tmp.txt
mv $2 $2.bak
mv ./tmp.txt $2

Commenting out a set of lines in a shell script

I was wondering if there is a way to comment out a set of lines in a shell script.
How could I do that? We can use /* */ in other programming languages.
This is most useful when I am converting/using/modifying another script
and I want to keep the original lines instead of deleting.
It seems a cumbersome job to find and prefix # for all the lines which are not used.
Lets say there are 100 lines in the script in consequent lines which are not to used.
I want to comment them all out in one go. Is that possible?
The most versatile and safe method is putting the comment into a void quoted
here-document, like this:
<<"COMMENT"
This long comment text includes ${parameter:=expansion}
`command substitution` and $((arithmetic++ + --expansion)).
COMMENT
Quoting the COMMENT delimiter above is necessary to prevent parameter
expansion, command substitution and arithmetic expansion, which would happen
otherwise, as Bash manual states and POSIX shell standard specifies.
In the case above, not quoting COMMENT would result in variable parameter
being assigned text expansion, if it was empty or unset, executing command
command substitution, incrementing variable arithmetic and decrementing
variable expansion.
Comparing other solutions to this:
Using if false; then comment text fi requires the comment text to be
syntactically correct Bash code whereas natural comments are often not, if
only for possible unbalanced apostrophes. The same goes for : || { comment text }
construct.
Putting comments into a single-quoted void command argument, as in :'comment
text', has the drawback of inability to include apostrophes. Double-quoted
arguments, as in :"comment text", are still subject to parameter expansion,
command substitution and arithmetic expansion, the same as unquoted
here-document contents and can lead to the side-effects described above.
Using scripts and editor facilities to automatically prefix each line in a
block with '#' has some merit, but doesn't exactly answer the question.
if false
then
...code...
fi
false always returns false so this will always skip the code.
You can also put multi-line comments using:
: '
comment1comment1
comment2comment2
comment3comment3
comment4comment4
'
As per the Bash Reference for Bourne Shell builtins
: (a colon)
: [arguments]
Do nothing beyond expanding arguments and performing redirections. The return status is zero.
Thanks to Ikram for pointing this out in the post Shell script put multiple line comment
You can use a 'here' document with no command to send it to.
#!/bin/bash
echo "Say Something"
<<COMMENT1
your comment 1
comment 2
blah
COMMENT1
echo "Do something else"
Wikipedia Reference
Text editors have an amazing feature called search and replace. You don't say what editor you use, but since shell scripts tend to be *nix, and I use VI, here's the command to comment lines 20 to 50 of some shell script:
:20,50s/^/#/
: || {
your code here
your code here
your code here
your code here
}
What if you just wrap your code into function?
So this:
cd ~/documents
mkdir test
echo "useless script" > about.txt
Becomes this:
CommentedOutBlock() {
cd ~/documents
mkdir test
echo "useless script" > about.txt
}
As per this site:
#!/bin/bash
foo=bar
: '
This is a test comment
Author foo bar
Released under GNU
'
echo "Init..."
# rest of script
Depending of the editor that you're using there are some shortcuts to comment a block of lines.
Another workaround would be to put your code in an "if (0)" conditional block ;)
This Perl one-liner comments out lines 1 to 3 of the file orig.sh inclusive (where the first line is numbered 0), and writes the commented version to cmt.sh.
perl -n -e '$s=1;$e=3; $_="#$_" if $i>=$s&&$i<=$e;print;$i++' orig.sh > cmt.sh
Obviously you can change the boundary numbers as required.
If you want to edit the file in place, it's even shorter:
perl -in -e '$s=1;$e=3; $_="#$_" if $i>=$s&&$i<=$e;print;$i++' orig.sh
Demo
$ cat orig.sh
a
b
c
d
e
f
$ perl -n -e '$s=1;$e=3; $_="#$_" if $i>=$s&&$i<=$e;print;$i++' orig.sh > cmt.sh
$ cat cmt.sh
a
#b
#c
#d
e
f

Resources