Using cat in a bash script : escaping troubles - bash

I'm very bad at regex and escaping characters.
I want to use the 'cat' command in a bash script like this :
echo `cat working-dir/*OUTPUT` ;
That should print on screen, every files in the working-dir that end with "OUTPUT" but this is not working
Later in that program, i would like to do this :
cat working-dir/*OUTPUT >> result_file.txt
But is not working either :(
Can you help me please?

Why are you using echo, or backticks, at all?
cat working-dir/*OUTPUT
Similarly,
cat working-dir/*OUTPUT >> result_file.txt
...certainly should work. Please provide a complete script for reproducing any failure that you see, including setup (creating working-dir, putting at least one file ending with OUTPUT into it, running the cat, and observing it to fail).

Related

Bash script: any way to collect remainder of command line as a string, including quote characters?

The following simplified version of a script I'll call logit obviously just appends everything but $1 in a text file, so I can keep track of time like this:
$ logit Started work on default theme
But bash expansion gets confused by quotes of any kind. What I'd like is to do things like
$ logit Don't forget a dark mode
But when that happens of course shell expansion rules cause a burp:
quote>
I know this works:
# Yeah yeah I can enclose it in quotes but I'd prefer not to
$ logit "Don't forget a dark mode"
Is there any way to somehow collect the remainder of the command line before bash gets to it, without having to use quotes around my command line?
Here's a minimal working version of the script.
#!/bin/bash
log_file=~/log.txt
now=$(date +"%T %r")
echo "${now} ${#:1}" >> $log_file
Is there any way to somehow collect the remainder of the command line before bash gets to it, without having to use quotes around my command line?
No. There is no "before bash gets into it" time. Bash reads the input you are typing, Bash parses the input you are typing, there is nothing in between or "before". There is only Bash.
You can: use a different shell or write your own. Note that quotes parsing like in shell is very common, you may consider that it could be better for you to understand and get used to it.
you can use a backslash "\" before the single quote
$ logit Don\'t forget a dark mode

Why bash script does not run well?

I write a code in Bash script and the Linux does not run it correctly and printed character instead of character’s value.
Can anyone help me?
Aside from the confusion between backtick and ', you are also over-using the sub-shell syntax. You do not need to use echo $(cat $LOOP). You can just run cat $LOOP directly.
#!/bin/bash
for FILE in $(ls); do
echo "Here is ${file}:"
cat ${FILE}
echo ""
done
A couple of points of style as well:
Name your variables after the thing they represent. The loop is iterating over files in the current directory, so the name FILE is more descriptive than LOOP.
It is a good idea to get in the habit of enclosing your variable references in ${ ... } instead of just prefixing them with $. In simple scripts like this, it does not make a difference, but when your scripts get more complicated, you can get into trouble when you do not clearly delineate variable names.

Bash Script Path Containing Space

I just have this simple script :
#!/bin/bash
mainDir="EVE-NG\ Repos"
mega-ls ahmedrafat#debugz-it.com:$mainDir
But I got this error :
[API:err: 08:40:34] Couldn't find "ahmedrafat#debugz-it.com:EVE-NG\ Repos"
When I enter the command natively in bash like this :
mega-ls ahmedrafat#debugz-it.com:EVE-NG\ Repos
It works, but inside the script, it doesn't.
Try typing this in at the shell:
mega-ls "ahmedrafat#debugz-it.com:EVE-NG Repos"
Does that clear things up? Inside quotes you don't need to escape spaces (and it doesn't work, sending \char instead).
Note that this is required all the way:
Myvar="this and that"
echo "$Myvar" #with quotes to get 1 arg

Why does this simple shell code give the output as "/dev/fd/11"?

I was trying out some redirection in my mac zsh shell.
I see that echo <(echo $c) outputs /dev/fd/11. I have no idea why this happens. Can someone explain?
Note: It doesn't matter if $c is initialised or not.
echo < '' returns zsh: no such file or directory: , so I am at a loss understanding what's going on.
Process expansion effectively "expands" to a file name. You are passing that file name as the argument to echo, which it dutifully writes back to standard output. If you had written
cat <(echo $c)
you would get as output, as I think you expected, the output of the command echo $c, because cat would open /dev/fd/11 for reading and output its contents.
Got the answer from here
https://unix.stackexchange.com/questions/17107/process-substitution-and-pipe
Looks like <(COMMAND) is slightly different that a the < (STDIN redirect) command
Pipes and input redirects shove content onto the STDIN stream. Process
substitution runs the commands, saves their output to a special
temporary file and then passes that file name in place of the command.
Whatever command you are using treats it as a file name. Note that the
file created is not a regular file but a named pipe that gets removed
automatically once it is no longer needed.

Why can I execute a command in a terminal window just fine but encounter an error in a bash script?

I've been organizing my music library as of late, and I'm trying to make everything "look" the same. All my songs should look like 04 John Barleycorn.m4a, but some of them, coming from multi-disk sets, look like 2-04 John Barleycorn.m4a. So I immediately thought, "Why not make a bash script to do all of this tedious work for me?" Little did I know, I would spend more time trying to figure out this "bug" than it would take to just do it by hand. Only one small difference: I wouldn't learn anything doing it by hand!
So here's my script:
#!/bin/bash
filename="/tmp/fileout.txt"
find . -name '?-*.???' > $filename
cat $filename | while read line
do
echo ${line:1}
newname=$(echo ${line%\/*}/${line#*-})
echo $newname
#mv \"$line\" \"$newname\"
done
It should be simple enough, right? It finds all the files with the multi-disk format, and puts them in a text file. Each line is then read back, reformated, and is "moved" to its new location/file name. (some parts are commented out since I want to make sure things "looked" good before moving files) However, when I first tried it out (after things "looked" good and removed the # in front of mv), I kept getting
mv: target `Barleycorn.m4a"' is not a directory
and I think that's because the spaces are not being escaped. I thought by putting quotes around it would solve it, but apparently not.
But I'll try to fix that later. Here's my buggy issue. I want to remove the first character (a period) in the file name (just an example...I don't really need to do this for any reason):
line="./Traffic/Smiling Phases/04 John Barleycorn.m4a"
echo ${line:1}
works just fine by typing that in command-line.
But in a bash script, it responds with:
/home/kyleowen/filerenamer.sh: 15: Bad substitution
I've gotten this error many times before when using ${var//foo/bar/} and other string operations within curly braces.
Why is it doing this? Doesn't my script effectively run all operations as if they were in command-line?
I would love a working bash script, sure...but I'm mainly asking why I'm getting a Bad substitution error when working with string operations. Thanks!
EDIT: I found my quite embarrassing mistake...never did I mention how I was executing these scripts. I was executing them as sh test.sh instead of bash test.sh. I assumed sh would execute them as your user's default shell, but I guess I'm wrong (or the default shell is not bash).
Thanks for the tips on input redirection! I'll post back what I have when I get something that works.
There are a number of quoting inconsistencies:
while read line
do
echo "${line:1}"
newname="${line%\/*}/${line#*-}"
echo "$newname"
# mv "$line" "$newname"
done < <(find . -name '?-*.???')
In general advice: use input redirection instead of piping into read
Reason: the while loop woulld execute in a subshell due to the pipe
Try it without the backslashes in the mv command line?
mv "$line" "$newname"
The backslashes makes mv look for files with literal double quotes in the filename.

Resources